DEV Community

SameX
SameX

Posted on

HarmonyOS Custom Edit Box and Shared Sandbox: Implementing Interactive Personalized Input Method and Edit Box

This article aims to deeply discuss the technical details of custom edit boxes and shared sandboxes in cross-application data sharing and is summarized based on actual development practices. Mainly serving as a carrier for technical sharing and exchange, it is inevitable that there may be errors and omissions. Colleagues are welcome to put forward valuable opinions and questions for common progress. This article is original content. Any form of reprint must indicate the source and original author.

In modern application development, users' demand for personalized experiences is growing. For input methods and edit boxes, achieving efficient interaction between the two and data persistence and sharing can greatly enhance the user experience. This article will introduce in detail how to build a customizable edit box application in the Huawei HarmonyOS Next system (API 12) and enable it to achieve data interaction with the input method application through a shared sandbox, including aspects such as requirement analysis, architecture design, key technology implementation, data consistency, and error handling.

I. Requirement Analysis and Overall Architecture Design

(I) Edit Box Requirements

Users expect the edit box to have basic operation functions such as custom input, deletion, and cursor control. At the same time, it should be able to be personalized according to personal habits, such as font size and color. These personalized settings should be able to be persisted and remain consistent in different application scenarios.

(II) The Role of Shared Sandbox

The shared sandbox plays a crucial role in this case. As an intermediate layer for data storage and sharing, it is used to persistently store user's personalized setting data, such as the style configuration of the edit box and historical input records. Through the shared sandbox, the input method application and the edit box application can achieve cross-application data sharing to ensure that users can obtain a consistent personalized experience when using the input method in different applications.

(III) Overall Architecture Design

We designed a three-layer architecture, including the edit box application layer, the shared sandbox layer, and the input method application layer. The edit box application layer is responsible for providing the user interface, receiving user input, and interacting with the shared sandbox to obtain and save personalized settings. The shared sandbox layer is responsible for managing data storage and sharing and providing a unified data access interface. When users input, the input method application layer communicates with the edit box application, obtains personalized settings and applies them to the input process, and at the same time saves relevant data (such as input history) to the shared sandbox.

II. Interaction Design between Edit Box and Input Method

(I) Implementing Input and Deletion Operation Monitoring in Custom Edit Box

In the development of custom edit boxes, we use the Text component as the text display component and manage the text content through state variables. At the same time, in order to implement monitoring of input and deletion operations, we need to obtain an instance of InputMethodController. The following is a simple example code:

import { inputMethod } from '@kit.IMEKit';

@Component
export struct CustomInput {
  @State inputText: string = "";
  private isAttach: boolean = false;
  private inputController: inputMethod.InputMethodController = inputMethod.getController();

  build() {
    Text(this.inputText)
   .fontSize(16)
   .width('100%')
   .lineHeight(40)
   .id('customInput')
   .onBlur(() => {
        this.off();
      })
   .height(45)
   .border({ color: '#554455', radius: 30, width: 1 })
   .maxLines(1)
   .onClick(() => {
        this.attachAndListener();
      });
  }

  async attachAndListener() {
    focusControl.requestFocus('CustomInput');
    await this.inputController.attach(true, {
      inputAttribute: {
        textInputType: inputMethod.TextInputType.TEXT,
        enterKeyType: inputMethod.EnterKeyType.SEARCH
      }
    });
    if (!this.isAttach) {
      this.inputController.on('insertText', (text) => {
        this.inputText += text;
      });
      this.inputController.on('deleteLeft', (length) => {
        this.inputText = this.inputText.substring(0, this.inputText.length - length);
      });
      this.isAttach = true;
    }
  }

  off() {
    this.isAttach = false;
    this.inputController.off('insertText');
    this.inputController.off('deleteLeft');
  }
}
Enter fullscreen mode Exit fullscreen mode

(II) Using InputMethodController to Bind the Input Method and Respond to Input in Real Time

By calling the attach method of InputMethodController, we can bind the input method to the edit box. After the binding is successful, the edit box can respond to the input method's input operations in real time and update the display content. At the same time, we can also set the relevant attributes of the input method as needed, such as input type and enter key type.

III. Data Sharing and Persistence Design of Shared Sandbox

(I) Configuring data-group-ids to Ensure that the Input Method Application and Edit Box Share the Sandbox

Configure data-group-ids in the application's profile file and make corresponding configurations in the module.json5 file where InputMethodExtensionAbility is located to achieve access permission settings for the shared sandbox for the input method application and the edit box application. The following is a simple configuration example (assuming data-group-ids is "myDataGroup"):

In the profile file:

{
  "app": {
    "data-group-ids": ["myDataGroup"]
  }
}
Enter fullscreen mode Exit fullscreen mode

In the module.json5 file:

{
  "module": {
    "extensionAbilities": [
      {
        "description": "InputMethodExtDemo",
        "icon": "Smedia:icon",
        "name": "InputMethodExtAbility",
        "srcEntry": "./ets/InputMethodExtensionAbility/InputMethodService.ts",
        "type": "inputMethod",
        "exported": true,
        "metadata": [
          {
            "name": "ohos.extension.input_method",
            "resource": "Sprofile:input_method_config"
          }
        ],
        "dataGroupIds": ["myDataGroup"]
      }
    ]
  }
}
Enter fullscreen mode Exit fullscreen mode

(II) Using getGroupDir to Achieve Data Persistence and Allow the Edit Box and Input Method to Share Settings and History

In the edit box application and the input method application, we can use the getGroupDir method to obtain the path of the shared sandbox, and then implement persistent storage and reading of data through file operations. For example, we can save the personalized settings of the edit box (such as font size, color, etc.) as a configuration file and read this file when the application starts to restore personalized settings. The following is a simple example of data persistence:

Saving settings in the edit box application:

import { inputMethod } from '@kit.IMEKit';

// Obtain the path of the shared sandbox
let groupDir = inputMethod.getGroupDir('myDataGroup');
let configPath = `${groupDir}/editor_config.json`;

// Save edit box settings
function saveEditorSettings(settings: any) {
  try {
    fs.writeFileSync(configPath, JSON.stringify(settings));
  } catch (error) {
    console.error('Failed to save settings:', error);
  }
}

// Read edit box settings
function loadEditorSettings(): any {
  try {
    let data = fs.readFileSync(configPath);
    return JSON.parse(data);
  } catch (error) {
    console.error('Failed to read settings:', error);
    return {};
  }
}
Enter fullscreen mode Exit fullscreen mode

Saving input history in the input method application:

import { inputMethod } from '@kit.IMEKit';

// Obtain the path of the shared sandbox
let groupDir = inputMethod.getGroupDir('myDataGroup');
let historyPath = `${groupDir}/input_history.json`;

// Save input history
function saveInputHistory(history: string[]) {
  try {
    fs.writeFileSync(historyPath, JSON.stringify(history));
  } catch (error) {
    console.error('Failed to save input history:', error);
  }
}

// Read input history
function loadInputHistory(): string[] {
  try {
    let data = fs.readFileSync(historyPath);
    return JSON.parse(data);
  } catch (error) {
    console.error('Failed to read input history:', error);
    return [];
  }
}
Enter fullscreen mode Exit fullscreen mode

IV. Cross-Process Data Consistency and Error Handling

(I) Handling Conflicts and Synchronization Issues in Cross-Process Data Transmission

In the process of cross-process data sharing, there may be situations where multiple processes access and modify shared data simultaneously, leading to data conflicts. To solve this problem, we can use methods such as lock mechanisms or message queues to achieve synchronous access to data. For example, when writing to shared data, obtain a lock first to ensure that only one process can perform a write operation at the same time.

(II) Error Handling: File Read-Write Exceptions and Shared Data Permission Issues

During the data persistence process, there may be file read-write exceptions, such as file not found, insufficient disk space, etc. We need to capture and handle these exceptions and provide users with friendly prompts. At the same time, for shared data permission issues, such as when the application does not have sufficient permission to access the shared sandbox, corresponding error handling is also required to ensure the stability and security of the application.

V. Sample Code and Architecture Diagram

(I) Sample Code

The following is an example code structure for simplified data reading and writing of custom edit boxes and shared sandboxes:

// Custom edit box component in the edit box application
import { inputMethod } from '@kit.IMEKit';
import fs from '@ohos.file.fs';

@Component
export struct CustomInput {
  //... Omitted part of the code

  // Save edit box settings
  saveSettings() {
    let settings = { fontSize: 16, color: '#000' }; // Assume saving font size and color here
    saveEditorSettings(settings);
  }

  // Load edit box settings
  loadSettings() {
    let settings = loadEditorSettings();
    if (settings.fontSize) {
      // Update the style of the edit box such as font size
    }
  }
}

// Shared sandbox data reading and writing functions
function saveEditorSettings(settings: any) {
  let groupDir = inputMethod.getGroupDir('myDataGroup');
  let configPath = `${groupDir}/editor_config.json`;
  try {
    fs.writeFileSync(configPath, JSON.stringify(settings));
  } catch (error) {
    console.error('Failed to save settings:', error);
  }
}

function loadEditorSettings(): any {
  let groupDir = inputMethod.getGroupDir('myDataGroup');
  let configPath = `${groupDir}/editor_config.json`;
  try {
    let data = fs.readFileSync(configPath);
    return JSON.parse(data);
  } catch (error) {
    console.error('Failed to read settings:', error);
    return {};
  }
}

// Saving input history in the input method application
function saveInputHistory(history: string[]) {
  let groupDir = inputMethod.getGroupDir('myDataGroup');
  let historyPath = `${groupDir}/input_history.json`;
  try {
    fs.writeFileSync(historyPath, JSON.stringify(history));
  } catch (error) {
    console.error('Failed to save input history:', error);
  }
}

function loadInputHistory(): string[] {
  let groupDir = inputMethod.getGroupDir('myDataGroup');
  let historyPath = `${groupDir}/input_history.json`;
  try {
    let data = fs.readFileSync(historyPath);
    return JSON.parse(data);
  } catch (error) {
    console.error('Failed to read input history:', error);
    return [];
  }
}
Enter fullscreen mode Exit fullscreen mode

(II) Architecture Diagram

The following is a schematic diagram of the cross-application data interaction architecture:

Application Layer Function Description
Edit box application Provides the user interface, receives user input, interacts with the shared sandbox to obtain and save personalized settings, and communicates with the input method through InputMethodController.
Shared sandbox Stores user personalized settings and data, provides data access interfaces, and realizes cross-application data sharing.
Input method application Interacts with the edit box application, obtains personalized settings and applies them to the input process, and saves data such as input history to the shared sandbox.

Through the above design and implementation, we have successfully built a system that supports data interaction between custom edit boxes and input method applications and uses shared sandboxes to achieve cross-application data sharing and persistence. In actual development, performance can be further optimized, more personalized setting options can be added, and the error handling mechanism can be improved. I hope this article can provide valuable references and guidance for scenarios involving edit box and input method interaction and data sharing in HarmonyOS application development.

Top comments (0)