• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# AutoFillExtensionAbility
2
3<!--Kit: Ability Kit-->
4<!--Subsystem: Ability-->
5<!--Owner: @hanchen45; @Luobniz21-->
6<!--Designer: @ccllee1-->
7<!--Tester: @lixueqing513-->
8<!--Adviser: @huipeizi-->
9
10## Overview
11
12The [AutoFillExtensionAbility](../reference/apis-ability-kit/js-apis-app-ability-autoFillExtensionAbility-sys.md) is an [ExtensionAbility](../reference/apis-ability-kit/js-apis-app-ability-extensionAbility.md) component of the AUTO_FILL_PASSWORD or AUTO_FILL_SMART type that provides the auto-fill service.
13
14The auto-fill service can be classified as follows:
15
16- Auto-fill for accounts and passwords: Saved accounts and passwords are automatically populated, improving the efficiency of information input.
17- Scenario-specific auto-fill: Information such as the mobile number and address is automatically populated based on the usage scenario.
18
19In this example, the party that provides the [AutoFillExtensionAbility](../reference/apis-ability-kit/js-apis-app-ability-autoFillExtensionAbility-sys.md) capability is called the provider, and the party that starts the AutoFillExtensionAbility is called the client.
20
21## Available APIs
22
23The table below describes the main APIs related to the auto-fill service. For details about other APIs, see [AutoFillRequest](../reference/apis-ability-kit/js-apis-inner-application-autoFillRequest-sys.md) and [AutoFillExtensionAbility](../reference/apis-ability-kit/js-apis-app-ability-autoFillExtensionAbility-sys.md).
24
25| API                                                    | Description                                                        |
26| ------------------------------------------------------------ | ------------------------------------------------------------ |
27| onFillRequest(session: UIExtensionContentSession, request: FillRequest, callback: FillRequestCallback): void | Called when an auto-fill request is initiated or a password is generated.            |
28| onSaveRequest(session: UIExtensionContentSession, request: SaveRequest, callback: SaveRequestCallback): void | Called when an automatic or manual save request is initiated.                |
29| FillRequestCallback.onSuccess(response: FillResponse): void  | Implements the callback for an auto-fill request, which is used to automatically fill in or generate a password. The callback can be used to notify the client of the success of the request.|
30
31## Developing the AutoFillExtensionAbility Provider
32
33### Lifecycle
34
35The [AutoFillExtensionAbility](../reference/apis-ability-kit/js-apis-app-ability-autoFillExtensionAbility-sys.md) provides the lifecycle callbacks [onCreate](../reference/apis-ability-kit/js-apis-app-ability-autoFillExtensionAbility-sys.md#oncreate), [onSessionDestroy](../reference/apis-ability-kit/js-apis-app-ability-autoFillExtensionAbility-sys.md#onsessiondestroy), [onForeground](../reference/apis-ability-kit/js-apis-app-ability-autoFillExtensionAbility-sys.md#onforeground), [onBackground](../reference/apis-ability-kit/js-apis-app-ability-autoFillExtensionAbility-sys.md#onbackground), [onDestroy](../reference/apis-ability-kit/js-apis-app-ability-autoFillExtensionAbility-sys.md#ondestroy), [onSaveRequest](../reference/apis-ability-kit/js-apis-app-ability-autoFillExtensionAbility-sys.md#onsaverequest), and [onFillRequest](../reference/apis-ability-kit/js-apis-app-ability-autoFillExtensionAbility-sys.md#onfillrequest). Override them as required.
36
37- **onCreate**: called to initialize the service logic when an AutoFillExtensionAbility is created.
38- **onSessionDestroy**: called when a UIExtensionContentSession instance is destroyed for the AutoFillExtensionAbility.
39- **onForeground**: called when the AutoFillExtensionAbility is switched from the background to the foreground.
40- **onBackground**: called when the AutoFillExtensionAbility is switched from the foreground to the background.
41- **onDestroy**: called to clear resources when the AutoFillExtensionAbility is destroyed.
42- **onSaveRequest**: called to trigger auto-save when form data exists and the page is to be switched.
43- **onFillRequest**: called to automatically fill in the account and password when a fill request is sent.
44
45### Implementing Auto-Fill for Accounts and Passwords
46
47Before implementing auto-fill for accounts and passwords, manually create an AutoFillExtensionAbility in the DevEco Studio project.
48
491. Set the bundle name of the AutoFillExtensionAbility provider.
50
51   In the [app.json5 file](../quick-start/app-configuration-file.md) in the **AppScope** directory, set **bundleName** to **com.ohos.passwordbox**. An example configuration is as follows:
52
53   ```json
54   "app": {
55     "bundleName": "com.ohos.passwordbox",
56      // ...
57   }
58   ```
59
602. Configuration information about this ExtensionAbility.
61
62   Configure an AutoFillExtensionAbility in the [module.json5 file](../quick-start/module-configuration-file.md) in the **entry/src/main/** directory. An example configuration is as follows:
63
64   ```json
65   "extensionAbilities": [
66      {
67        "name": "AutoFillAbility",
68        "srcEntry": "./ets/autofillability/AutoFillAbility.ets",
69        // ...
70        "type": "autoFill/password"
71      }
72   ]
73   ```
74
753. Implement auto-fill and auto-save.
76
77   1. Right-click the **ets** directory, and choose **New > Directory** to create a directory named **autofillability**.
78
79   2. Right-click the **autofillability** directory, and choose **New > File** to create a file named **AutoFillAbility.ets**. An example code snippet is as follows:
80
81      ```ts
82      import { hilog } from '@kit.PerformanceAnalysisKit';
83      import { AutoFillExtensionAbility, autoFillManager, UIExtensionContentSession } from '@kit.AbilityKit';
84
85      class AutoFillAbility extends AutoFillExtensionAbility {
86        // ...
87        // The onFillRequest lifecycle callback is triggered when the auto-fill service initiates an auto-fill request.
88        onFillRequest(session: UIExtensionContentSession, request: autoFillManager.FillRequest, callback: autoFillManager.FillRequestCallback) {
89          hilog.info(0x0000, 'testTag', '%{public}s', 'autofill onFillRequest');
90          try {
91            // Save the page data and callback data carried in onFillRequest.
92            let obj: Record<string, UIExtensionContentSession | autoFillManager.FillRequestCallback | autoFillManager.ViewData> = {
93              'session': session,
94              'fillCallback': callback, // The auto-fill processing result is returned to the client through this callback.
95              'viewData': request.viewData, // Assemble the data to be populated to viewData and return the data to the client through the callback.
96            };
97            let storageFill: LocalStorage = new LocalStorage(obj);
98            // Load the auto-fill processing page.
99            session.loadContent('autofillpages/AutoFillPassWord', storageFill);
100          } catch (err) {
101            hilog.error(0x0000, 'testTag', '%{public}s', 'autofill failed to load content');
102          }
103        }
104
105        // The onSaveRequest lifecycle callback is triggered when the auto-save service initiates an auto-save request.
106        onSaveRequest(session: UIExtensionContentSession, request: autoFillManager.SaveRequest, callback: autoFillManager.SaveRequestCallback): void {
107          hilog.info(0x0000, 'testTag', '%{public}s', 'autofill onSaveRequest');
108          try {
109            let obj: Record<string, UIExtensionContentSession | autoFillManager.SaveRequestCallback | autoFillManager.ViewData> = {
110              'session': session,
111              'saveCallback': callback, // The auto-save processing result is returned to the client through this callback.
112              'viewData': request.viewData, // Assemble the data to be populated to viewData and return the data to the client through the callback.
113            }
114            // Save the page data and callback data carried in onSaveRequest.
115            let storageSave: LocalStorage = new LocalStorage(obj);
116            // Load the auto-save processing page.
117            session.loadContent('autofillpages/SavePage', storageSave);
118          } catch (err) {
119            hilog.error(0x0000, 'testTag', '%{public}s', 'autofill failed');
120          }
121        }
122      }
123      ```
124
1254. Build the auto-fill processing page.
126
127   1. Right-click the **ets** directory, and choose **New > Directory** to create a directory named **autofillpages**.
128
129   2. Right-click the **autofillpages** directory, and choose **New > File** to create a file named **AutoFillPassWord.ets**.
130
131   3. When users touch the account or password text box on the page, the auto-fill framework sends an auto-fill request to the auto-fill service to trigger the [onFillRequest](../reference/apis-ability-kit/js-apis-app-ability-autoFillExtensionAbility-sys.md#onfillrequest) lifecycle callback. In the **onFillRequest** lifecycle callback, display the page that shows the available accounts and passwords (implemented by **AutoFillPassWord.ets**).
132
133      ```ts
134      import { autoFillManager } from '@kit.AbilityKit';
135
136      // Assemble the data to be populated to viewData and use the onSuccess callback to return the data to the client for auto-fill.
137      function successFunc(data: autoFillManager.ViewData, target: string, fillCallback?: autoFillManager.FillRequestCallback) {
138        console.info(`data.pageNodeInfos.length`, data.pageNodeInfos.length);
139        for (let i = 0; i < data.pageNodeInfos.length; i++) {
140          console.info(`data.pageNodeInfos[i].isFocus`, data.pageNodeInfos[i].isFocus);
141          if (data.pageNodeInfos[i].isFocus == true) {
142            data.pageNodeInfos[i].value = target;
143            break;
144          }
145        }
146        if (fillCallback) {
147          let response: autoFillManager.FillResponse = { viewData: data };
148          fillCallback.onSuccess(response);
149        }
150      }
151
152      function failFunc(fillCallback?: autoFillManager.FillRequestCallback) {
153        if (fillCallback) {
154          fillCallback.onFailure();
155        }
156      }
157
158      function cancelFunc(fillContent?: string, fillCallback?: autoFillManager.FillRequestCallback) {
159        if (fillCallback) {
160          try {
161            fillCallback.onCancel(fillContent);
162          } catch (error) {
163            console.error('fillContent undefined: ', JSON.stringify(error));
164          }
165        }
166      }
167
168      @Entry
169      @Component
170      struct AutoFillControl {
171        storage: LocalStorage | undefined = this.getUIContext().getSharedLocalStorage();
172        fillCallback: autoFillManager.FillRequestCallback | undefined = this.storage?.get<autoFillManager.FillRequestCallback>('fillCallback');
173        viewData: autoFillManager.ViewData | undefined = this.storage?.get<autoFillManager.ViewData>('viewData');
174
175        build() {
176          Column() {
177            Flex({ justifyContent: FlexAlign.Start, alignItems: ItemAlign.Center }) {
178              Text('Select a saved account and password')
179                .fontWeight(500)
180                .fontFamily('HarmonyHeiTi-Medium')
181                .fontSize(20)
182                .fontColor('#000000')
183                .margin({ left: '4.4%' })
184            }.margin({ top: '8.8%', left: '4.9%' }).height('7.2%')
185
186            Row() {
187              Column() {
188                List({ space: 10, initialIndex: 0 }) {
189                  ListItem() {
190                    Text('15501212262')
191                      .width('100%')
192                      .height(40)
193                      .fontSize(16)
194                      .textAlign(TextAlign.Center)
195                      .borderRadius(5)
196                  }
197                  .onClick(() => {
198                    if (this.viewData != undefined) {
199                      // Populate the selected account and password in the client.
200                      successFunc(this.viewData, '15501212262', this.fillCallback);
201                    }
202                  })
203                }
204                // ...
205                .listDirection(Axis.Vertical)
206                .scrollBar(BarState.Off)
207                .friction(0.6)
208                .divider({ strokeWidth: 1, color: '#fff5eeee', startMargin: 20, endMargin: 20 })
209                .edgeEffect(EdgeEffect.Spring)
210                .onScrollIndex((firstIndex: number, lastIndex: number, centerIndex: number) => {
211                  console.info('first' + firstIndex)
212                  console.info('last' + lastIndex)
213                  console.info('center' + centerIndex)
214                })
215                .onDidScroll((scrollOffset: number, scrollState: ScrollState) => {
216                  console.info(`onDidScroll scrollState = ScrollState` + scrollState + `scrollOffset = ` + scrollOffset)
217                })
218              }
219              .width('100%')
220              .shadow(ShadowStyle.OUTER_FLOATING_SM)
221              .margin({ top: 50 })
222            }
223
224            Row() {
225              Button("Cancel")
226                .onClick(() => {
227                  // Call cancelFunc() to notify the client when auto-fill is canceled.
228                  cancelFunc(undefined, this.fillCallback);
229                })
230                .margin({ top: 30, bottom: 10, left: 10, right: 10 })
231
232              Button("Failure")
233                .onClick(() => {
234                  // Call failFunc() to notify the client that auto-fill fails when the account and password are not obtained.
235                  failFunc(this.fillCallback);
236                })
237                .margin({ top: 30, bottom: 10, left: 10, right: 10 })
238            }
239            .backgroundColor('#f1f3f5').height('100%')
240          }
241        }
242      }
243      ```
244
2455. Build the auto-save processing page.
246
247   1. Right-click the **autofillpages** directory, and choose **New > File** to create a file named **SavePage.ets**.
248
249   2. When information exists in the **TextInput** component, trigger the [onSaveRequest](../reference/apis-ability-kit/js-apis-app-ability-autoFillExtensionAbility-sys.md#onsaverequest) lifecycle callback during page redirection (a user touches the login button). In the **onSaveRequest** callback, display the information save processing page (implemented by **SavePage.ets**).
250
251      ```ts
252      import { autoFillManager } from '@kit.AbilityKit';
253      import { hilog } from '@kit.PerformanceAnalysisKit';
254
255      function SuccessFunc(success : boolean, saveRequestCallback?: autoFillManager.SaveRequestCallback) {
256        if (saveRequestCallback) {
257          if (success) {
258            saveRequestCallback.onSuccess();
259            return;
260          }
261          saveRequestCallback.onFailure();
262        }
263        hilog.error(0x0000, "testTag", "saveRequestCallback is nullptr!");
264      }
265
266      @Entry
267      @Component
268      struct SavePage {
269        @State message: string = 'Save Account?'
270        storage: LocalStorage | undefined = this.getUIContext().getSharedLocalStorage();
271        saveRequestCallback: autoFillManager.SaveRequestCallback | undefined = this.storage?.get<autoFillManager.SaveRequestCallback>('saveCallback');
272
273        build() {
274          Row() {
275            Column() {
276              Text(this.message)
277                .fontSize(35)
278                .fontWeight(FontWeight.Bold)
279              Row() {
280                // Call onSuccess() (upon the touch of the save button) to notify the client that the form data is saved successfully.
281                Button("save")
282                  .type(ButtonType.Capsule)
283                  .fontSize(20)
284                  .margin({ top: 30, right: 30 })
285                  .onClick(() => {
286                    SuccessFunc(true, this.saveRequestCallback);
287                  })
288                // Call onFailure() (upon the touch of the back button) to notify the client that the user cancels saving the form data or saving the form data fails.
289                Button("back")
290                  .type(ButtonType.Capsule)
291                  .fontSize(20)
292                  .margin({ top: 30, left: 30 })
293                  .onClick(() => {
294                    SuccessFunc(false, this.saveRequestCallback);
295                  })
296              }
297            }
298            .width('100%')
299          }
300          .height('100%')
301        }
302      }
303      ```
304
305### Implementing Scenario-specific Auto-Fill
306
307For details about the types of scenario-specific auto-fill, see [AutoFillType](../reference/apis-ability-kit/js-apis-inner-application-autoFillType-sys.md).
308
309Before implementing scenario-specific auto-fill, you need to create a SmartAutoFillExtensionAbility object in the DevEco Studio project.
310
3111. Set the bundle name of the AutoFillExtensionAbility provider.
312
313   In the [app.json5 file](../quick-start/app-configuration-file.md) in the **AppScope** directory, set **bundleName** to **com.ohos.textautofill**. An example configuration is as follows:
314
315   ```json
316   "app": {
317     "bundleName": "com.ohos.textautofill",
318      // ...
319   }
320   ```
321
3222. Configuration information about this ExtensionAbility.
323
324   Configure an AutoFillExtensionAbility in the [module.json5 file](../quick-start/module-configuration-file.md) in the **entry/src/main/** directory. An example configuration is as follows:
325
326   ```json
327   "extensionAbilities": [
328      {
329         "name": "AutoFillAbility",
330         "srcEntry": "./ets/autofillability/AutoFillAbility.ets",
331         // ...
332         "type": "autoFill/smart"
333      }
334   ]
335   ```
336
3373. The implementation of the scenario-specific auto-fill service is basically the same as that of auto-fill for accounts and passwords. For details, see [Implementing Auto-Fill for Accounts and Passwords](#implementing-auto-fill-for-accounts-and-passwords).
338
339## Developing the AutoFillExtensionAbility Client
340
341You can click the auto-fill component on the home page to start the [AutoFillExtensionAbility](../reference/apis-ability-kit/js-apis-app-ability-autoFillExtensionAbility-sys.md). For example, you can add the following component to the main page:
342
343### Component That Supports Auto-Fill of Accounts and Passwords
344
345```ts
346@Entry
347@Component
348struct Index {
349  loginBtnColor: string = '#bfdbf9';
350
351  build() {
352    Column() {
353      Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
354        Text('Welcome!')
355          .fontSize(24)
356          .fontWeight(500)
357          .fontFamily('HarmonyHeiTi-Medium')
358          .fontColor('#182431')
359      }.margin({ top: '32.3%' }).width('35%').height('4.1%')
360
361      // Add a text box of the account type.
362      List() {
363        ListItemGroup({ style: ListItemGroupStyle.CARD }) {
364          ListItem({ style: ListItemStyle.CARD }) {
365            TextInput({placeholder: 'Enter an account.'})
366              .type(InputType.USER_NAME)
367              .fontFamily('HarmonyHeiTi')
368              .fontColor('#182431')
369              .fontWeight(400)
370              .fontSize(16)
371              .height('100%')
372              .id('userName')
373              .backgroundColor('#FFFFFF')
374              .onChange((value: string) => {
375                if (value) {
376                  this.loginBtnColor = '#007DFF';
377                } else {
378                  this.loginBtnColor = '#bfdbf9';
379                }
380              })
381              .enableAutoFill(true)
382          }.padding(0)
383
384          // Add a text box of the password type.
385          ListItem({ style: ListItemStyle.CARD }) {
386            TextInput({placeholder: 'Enter the password.'})
387              .type(InputType.Password)
388              .fontFamily('HarmonyHeiTi')
389              .fontColor('#182431')
390              .fontWeight(400)
391              .fontSize(16)
392              .height('100%')
393              .backgroundColor('#FFFFFF')
394              .id('passWord')
395              .onChange((value: string) => {
396                if (value) {
397                  this.loginBtnColor = '#007DFF';
398                } else {
399                  this.loginBtnColor = '#bfdbf9';
400                }
401              })
402              .enableAutoFill(true)
403          }.padding(0)
404        }
405        .backgroundColor('#FFFFFF')
406        .divider({ strokeWidth: 0.5, color: '#f1f3f5', startMargin: 15, endMargin: 15 })
407      }
408      .borderRadius(24)
409      .width('93.3%')
410      .height('16%')
411      .margin({ top: '8.6%' })
412    }
413  }
414}
415```
416
417### Component That Supports Scenario-Specific Auto-Fill
418
419```ts
420@Entry
421@Component
422struct Index {
423  @State inputTxt: string = '';
424
425  build() {
426    Column() {
427      Column() {
428        Flex({ justifyContent: FlexAlign.Start, alignItems: ItemAlign.Center }) {
429          Text ('Scenario-specific population')
430            .fontWeight(500)
431            .fontFamily('HarmonyHeiTi-Medium')
432          // ...
433        }
434        .margin({ top: '14.2%' }).height('7.2%')
435
436        Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
437          Column() {
438            Row() {
439              Text('Set the type.')
440                .fontColor('#99000000')
441                .fontSize(14)
442                .fontWeight(400)
443                .textAlign(TextAlign.Start)
444                .width('91%')
445                .margin({ top: 5, left: -7.5 })
446            }
447
448            Row() {
449              TextInput({ placeholder: 'Input content', text: this.inputTxt })
450                .contentType(ContentType.FULL_PHONE_NUMBER) // Scenario-specific automatic population
451                .height('9.4%')
452                .width('91%')
453                .fontWeight(FontWeight.Bolder)
454                .placeholderColor('#99000000')
455                .backgroundColor('#ffffffff')
456                .id('password1')
457                .fontSize(16)
458                .fontWeight(400)
459                .borderStyle(BorderStyle.Solid)
460                .enableAutoFill(true)
461                .borderRadius(25)
462                .margin({ top: '8vp' })
463            }
464          }.margin({ top: '7.1%' })
465        }
466
467
468        Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
469          Column() {
470            Row() {
471              Text('Set the type to name')
472                .fontColor('#99000000')
473                .fontSize(14)
474                .fontWeight(400)
475                .textAlign(TextAlign.Start)
476                .width('91%')
477                .margin({ top: 5, left: -7.5 })
478            }
479
480            Row() {
481              TextInput({ placeholder: 'Name', text: this.inputTxt })
482                .contentType(ContentType.PERSON_FULL_NAME) // Scenario-specific automatic population
483                .height('9.4%')
484                .width('91%')
485                .fontWeight(FontWeight.Bold)
486                .placeholderColor('#99000000')
487                .backgroundColor('#ffffffff')
488                .fontSize(16)
489                .fontWeight(400)
490                .id('password3')
491                .borderStyle(BorderStyle.Solid)
492                .enableAutoFill(true)
493                .borderRadius(25)
494                .onChange(() => {
495                })
496                .margin({ top: '8vp' })
497            }
498          }
499        }
500        .margin({ top: '20vp' })
501      }.height('70%')
502    }
503    .backgroundColor('#ffffff').height('100%')
504  }
505}
506```
507