• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# InputMethodExtensionAbility开发指南
2
3[InputMethodExtensionAbility](../reference/apis/js-apis-inputmethod-extension-ability.md)是inputMethod类型的ExtensionAbility组件,提供输入法框架服务相关扩展能力。
4
5[InputMethodExtensionAbility](../reference/apis/js-apis-inputmethod-extension-ability.md)可以被其他组件启动或连接,并根据调用者的请求信息在后台处理相关事务。
6
7
8InputMethodExtensionAbility通过[InputMethodExtensionContext](../reference/apis/js-apis-inputmethod-extension-context.md)提供相关能力。
9
10
11## 实现一个输入法应用
12
13[InputMethodExtensionAbility](../reference/apis/js-apis-inputmethod-extension-ability.md)提供了onCreate()和onDestory()生命周期回调,根据需要重写对应的回调方法。InputMethodExtensionAbility的生命周期如下:
14
15- **onCreate**
16  服务被首次创建时触发该回调,开发者可以在此进行一些初始化的操作,例如注册公共事件监听等。
17
18  > **说明:**
19  > 如果服务已创建,再次启动该InputMethodExtensionAbility不会触发onCreate()回调。
20
21- **onDestroy**
22  当不再使用服务且准备将该实例销毁时,触发该回调。开发者可以在该回调中清理资源,如注销监听等。
23
24
25## 开发步骤
26
27开发者在实现一个输入法应用时,需要在DevEco Studio工程中新建一个InputMethodExtensionAbility,具体步骤如下:
28
29在工程Module对应的ets目录下,右键选择“New > Extention Ability > InputMethod”,即可创建出InputMethodExtensionAbility的最小化模板。
30
31> **说明:**
32> 在编译输入法应用时,要使用system_basic级别的签名,否则无法拉起输入法键盘。
33> [签名指导](https://developer.harmonyos.com/cn/docs/documentation/doc-guides/ohos-auto-configuring-signature-information-0000001271659465)
34
35最小化模板为一个最基本的输入法应用,包含软键盘拉起以及输入删除功能。后续开发者可在此基础上添加功能,如隐藏键盘等,实现自己的输入法应用。
36
37最小化模板主要包含四个文件,分别为KeyboardController.tsInputMethodService.tsIndex.ets以及KeyboardKeyData.ts。目录如下:
38
39```
40/src/main/
41├── ets/inputmethodextability
42│   └──model/KeyboardController.ts			# 显示键盘
43│   └──InputMethodService.ts				# 自定义类继承InputMethodExtensionAbility并加上需要的生命周期回调
44│   └──pages
45│      └── Index.ets						# 绘制键盘,添加输入删除功能
46│      └── KeyboardKeyData.ts			    # 键盘属性定义
47├── resources/base/profile/main_pages.json
48```
49
50## 文件介绍
51
521. InputMethodService.ts文件。
53
54InputMethodService.ts文件中,增加导入InputMethodExtensionAbility的依赖包,自定义类继承InputMethodExtensionAbility并加上需要的生命周期回调。
55
56   ```ts
57   import InputMethodExtensionAbility from '@ohos.InputMethodExtensionAbility';
58   import { KeyboardController } from './model/KeyboardController'
59
60   export default class InputDemoService extends InputMethodExtensionAbility {
61     private keyboardController: KeyboardController;
62
63     onCreate(want) {
64       this.keyboardController = new KeyboardController(this.context);
65       this.keyboardController.onCreate();  // 初始化窗口并注册对输入法框架的事件监听
66     }
67
68     onDestroy() {
69       console.log("onDestroy.");
70       this.context.destroy();
71     }
72   }
73   ```
74
752. KeyboardController.ts文件。
76
77   ```ts
78   import inputMethodEngine from '@ohos.inputMethodEngine';
79   import display from '@ohos.display';
80   import windowManager from '@ohos.window';
81
82   // 调用输入法框架的getInputMethodAbility方法获取实例,并由此实例调用输入法框架功能接口
83   globalThis.inputAbility = inputMethodEngine.getInputMethodAbility();
84
85   export class KeyboardController {
86     mContext;	// 保存InputMethodExtensionAbility中的context属性
87     WINDOW_TYPE_INPUT_METHOD_FLOAT = 2105;		// 定义窗口类型,2105代表输入法窗口类型,用于创建输入法应用窗口
88     windowName = 'inputApp';
89     private windowHeight: number = 0;
90     private windowWidth: number = 0;
91     private nonBarPosition: number = 0;
92     private isWindowShowing: boolean = false;
93
94     constructor(context) {
95       this.mContext = context;
96     }
97
98     public onCreate(): void
99     {
100       this.initWindow();				// 初始化窗口
101       this.registerListener();		// 注册对输入法框架的事件监听
102     }
103
104     public onDestroy(): void			// 应用生命周期销毁
105     {
106       this.unRegisterListener();		// 注销事件监听
107       let win = windowManager.findWindow(this.windowName);
108       win.destroyWindow();				// 销毁窗口
109       this.mContext.terminateSelf();	// 销毁InputMethodExtensionAbility服务
110     }
111
112     private initWindow(): void		// 初始化窗口
113     {
114       let dis = display.getDefaultDisplaySync();
115       let dWidth = dis.width;
116       let dHeight = dis.height;
117       let keyHeightRate = 0.47;
118       let keyHeight = dHeight * keyHeightRate;
119       this.windowWidth = dWidth;
120       this.windowHeight = keyHeight;
121       this.nonBarPosition = dHeight - keyHeight;
122
123       let config = {
124         name: this.windowName,
125         windowType: this.WINDOW_TYPE_INPUT_METHOD_FLOAT,
126         ctx: this.mContext
127       }
128       windowManager.createWindow(config).then((win) => {	// 根据窗口类型创建窗口
129         win.resize(dWidth, keyHeight).then(() => {
130           win.moveWindowTo(0, this.nonBarPosition).then(() => {
131             win.setUIContent('pages/InputMethodExtAbility/Index').then(() => {
132             });
133           });
134         });
135       });
136     }
137
138     private registerListener(): void
139     {
140       this.registerInputListener();	// 注册对输入法框架服务的监听
141       globalThis.inputAbility.on('keyboardShow', () => {	// 注册显示键盘事件监听
142         if (this.isWindowShowing) {
143           return;
144         }
145         this.isWindowShowing = true;
146         this.showHighWindow();	// 显示窗口
147       });
148       ...
149       // 注册隐藏键盘事件监听等
150     }
151
152     private registerInputListener() {		// 注册对输入法框架服务的开启及停止事件监听
153       globalThis.inputAbility.on('inputStart', (kbController, textInputClient) => {
154         globalThis.textInputClient = textInputClient;		// 此为输入法客户端实例,由此调用输入法框架提供给输入法应用的功能接口
155         globalThis.keyboardController = kbController;
156       })
157       globalThis.inputAbility.on('inputStop', (imeId) => {
158         if (imeId == "包名/Ability名") {
159           this.onDestroy();
160         }
161       });
162     }
163
164     private unRegisterListener(): void
165     {
166       globalThis.inputAbility.off('inputStart');
167       globalThis.inputAbility.off('inputStop', () => {});
168       globalThis.inputAbility.off('keyboardShow');
169     }
170
171     private showHighWindow() {
172       let win = windowManager.findWindow(this.windowName)
173       win.resize(this.windowWidth, this.windowHeight).then(() => {
174         win.moveWindowTo(0, this.nonBarPosition).then(() => {
175           win.showWindow().then(() => {
176             this.isWindowShowing = false;
177           })
178         })
179       })
180     }
181   }
182   ```
183
1843. KeyboardKeyData.ts文件。
185
186   定义软键盘的按键显示内容。
187
188   ```ts
189   export interface sourceListType {
190     content: string,
191   }
192
193   export let numberSourceListData: sourceListType[] = [
194     {
195       content: '1'
196     },
197     {
198       content: '2'
199     },
200     {
201       content: '3'
202     },
203     {
204       content: '4'
205     },
206     {
207       content: '5'
208     },
209     {
210       content: '6'
211     },
212     {
213       content: '7'
214     },
215     {
216       content: '8'
217     },
218     {
219       content: '9'
220     },
221     {
222       content: '0'
223     }
224   ]
225   ```
226
2274. Index.ets文件。
228
229   主要描绘了具体按键功能。如按下数字键,就会将数字内容在输入框中打印出来,按下删除键,就会将内容删除。
230
231   同时在resources/base/profile/main_pages.json文件的src字段中添加此文件路径。
232
233   ```ets
234   import { numberSourceListData, sourceListType } from './keyboardKeyData'
235
236   @Component
237   struct keyItem {
238     private keyValue: sourceListType
239     @State keyBgc: string = "#fff"
240     @State keyFontColor: string = "#000"
241
242     build() {
243       Column() {
244         Flex({ direction: FlexDirection.Column,
245           alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
246           Text(this.keyValue.content).fontSize(20).fontColor(this.keyFontColor)
247         }
248       }
249       .backgroundColor(this.keyBgc)
250       .borderRadius(6)
251       .width("8%")
252       .height("65%")
253       .onTouch((event: TouchEvent) => {
254         if (event.type === TouchType.Down) {
255           globalThis.textInputClient.insertText(this.keyValue.content);
256         }
257       })
258     }
259   }
260
261   // 删除组件
262   @Component
263   export struct deleteItem {
264     @State keyBgc: string = "#fff"
265     @State keyFontColor: string = "#000"
266
267     build() {
268       Column() {
269         Flex({ direction: FlexDirection.Column,
270           alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
271           Text("删除").fontSize(20).fontColor(this.keyFontColor)
272         }
273       }
274       .backgroundColor(this.keyBgc)
275       .width("13%")
276       .borderRadius(6)
277       .onTouch((event: TouchEvent) => {
278         if (event.type === TouchType.Down) {
279           globalThis.textInputClient.deleteForward(1);
280         }
281       })
282     }
283   }
284
285   // 数字键盘
286   @Component
287   struct numberMenu {
288     private numberList: sourceListType[]
289
290     build() {
291       Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.SpaceEvenly }) {
292         Flex({ justifyContent: FlexAlign.SpaceBetween }) {
293           ForEach(this.numberList, (item: sourceListType) => {  // 数字键盘第一行
294             keyItem({ keyValue: item })
295           }, (item: sourceListType) => item.content);
296         }
297         .padding({ top: "2%" })
298         .width("96%")
299         .height("25%")
300
301         Flex({ justifyContent: FlexAlign.SpaceBetween }) {
302           deleteItem()
303         }
304         .width("96%")
305         .height("25%")
306       }
307     }
308   }
309
310   @Entry
311   @Component
312   struct Index {
313     private numberList: sourceListType[] = numberSourceListData
314
315     build() {
316       Stack() {
317         Flex({
318           direction: FlexDirection.Column,
319           alignItems: ItemAlign.Center,
320           justifyContent: FlexAlign.End
321         }) {
322               Flex({
323                 direction: FlexDirection.Column,
324                 alignItems: ItemAlign.Center,
325                 justifyContent: FlexAlign.SpaceBetween
326               }) {
327                 numberMenu({
328                   numberList: this.numberList
329                 })
330               }
331               .align(Alignment.End)
332               .width("100%")
333               .height("75%")
334             }
335         .height("100%").align(Alignment.End).backgroundColor("#cdd0d7")
336       }
337       .position({ x: 0, y: 0 }).zIndex(99999)
338     }
339   }
340   ```
341
3425. 在工程Module对应的[module.json5配置文件](../quick-start/module-configuration-file.md)中注册InputMethodExtensionAbility,type标签需要设置为“inputMethod”,srcEntrance标签表示当前InputMethodExtensionAbility组件所对应的代码路径。
343
344   ```ts
345   {
346     "module": {
347       // ...
348       "extensionAbilities": [
349         {
350           "description": "inputMethod",
351           "icon": "$media:icon",
352           "name": "InputMethodExtAbility",
353           "srcEntrance": "./ets/inputmethodextability/InputMethodService.ts",
354           "type": "inputMethod",
355           "visible": true,
356         }
357       ]
358     }
359   }
360   ```
361
362
363
364
365## 相关实例
366
367针对InputMethodExtensionAbility开发,有以下相关实例可供参考:
368
369- [Kika输入法](https://gitee.com/openharmony/applications_app_samples/tree/OpenHarmony-3.2-Release/CompleteApps/KikaInput)