1# Developing a JS Widget (Stage Model) 2<!--Kit: Form Kit--> 3<!--Subsystem: Ability--> 4<!--Owner: @cx983299475--> 5<!--Designer: @xueyulong--> 6<!--Tester: @chenmingze--> 7<!--Adviser: @Brilliantry_Rui--> 8The stage model is supported since API version 9. It is the mainstream model with a long evolution plan. This model is object-oriented and provides open application components as classes. You can derive application components for capability expansion. 9 10## Available APIs 11 12The **FormExtensionAbility** class has the following APIs. For details, see [FormExtensionAbility](../reference/apis-form-kit/js-apis-app-form-formExtensionAbility.md). 13 14| Name | Description| 15| -------- | -------- | 16| onAddForm(want: Want): formBindingData.FormBindingData | Called to notify the widget provider that a widget is being created.| 17| onCastToNormalForm(formId: string): void | Called to notify the widget provider that a temporary widget is being converted to a normal one.| 18| onUpdateForm(formId: string): void | Called to notify the widget provider that a widget is being updated.| 19| onChangeFormVisibility(newStatus: Record<string, number>): void | Called to notify the widget provider that the widget visibility status is being changed.| 20| onFormEvent(formId: string, message: string): void | Called to instruct the widget provider to process a widget event.| 21| onRemoveForm(formId: string): void | Called to notify the widget provider that a widget is being destroyed.| 22| onConfigurationUpdate(newConfig: Configuration): void | Called when the configuration of the environment where the widget is running is being updated.| 23 24The following table lists some APIs provided by the **formProvider** class. For details about the APIs, see [API Reference](../reference/apis-form-kit/js-apis-app-form-formProvider.md). 25 26| Name| Description| 27| -------- | -------- | 28| setFormNextRefreshTime(formId: string, minute: number, callback: AsyncCallback<void>): void | Sets the next refresh time for a widget. This API uses an asynchronous callback to return the result.| 29| setFormNextRefreshTime(formId: string, minute: number): Promise<void> | Sets the next refresh time for a widget. This API uses a promise to return the result.| 30| updateForm(formId: string, formBindingData: formBindingData.FormBindingData, callback: AsyncCallback<void>): void | Updates a widget. This API uses an asynchronous callback to return the result.| 31| updateForm(formId: string, formBindingData: formBindingData.FormBindingData): Promise<void> | Updates a widget. This API uses a promise to return the result.| 32 33The **FormBindingData** class has the following APIs. For details, see [FormBindingData](../reference/apis-form-kit/js-apis-app-form-formBindingData.md). 34 35| Name| Description| 36| -------- | -------- | 37| createFormBindingData(obj?: Object \| string): FormBindingData | Creates a **FormBindingData** object.| 38 39 40## How to Develop 41 42The widget provider development based on the [stage model](../application-models/stage-model-development-overview.md) involves the following key steps: 43 44- [Creating a FormExtensionAbility Instance](#creating-a-formextensionability-instance): Develop the lifecycle callback functions of FormExtensionAbility. 45 46- [Configuring the Widget Configuration Files](#configuring-the-widget-configuration-files): Configure the application configuration file **module.json5** and profile configuration file. 47 48- [Persistently Storing Widget Data](#persistently-storing-widget-data): Manage widget data persistence. 49 50- [Updating Widget Data](#updating-widget-data): Call **updateForm()** to update the information displayed in a widget. 51 52- [Developing the Widget UI Page](#developing-the-widget-ui-page): Use HML+CSS+JSON to develop a JS widget UI page. 53 54- [Developing Widget Events](#developing-widget-events): Add the router and message events for a widget. 55 56 57### Creating a FormExtensionAbility Instance 58 59To create a widget in the stage model, you need to implement the lifecycle callbacks of FormExtensionAbility. For details about how to generate a service widget template, see <!--RP1-->[Developing a Service Widget](https://developer.huawei.com/consumer/en/doc/harmonyos-guides-V5/ide-service-widget-V5)<!--RP1End-->. 60 611. Import related modules to **EntryFormAbility.ets**. 62 ```ts 63 import { Want } from '@kit.AbilityKit'; 64 import { formBindingData, FormExtensionAbility, formInfo, formProvider } from '@kit.FormKit'; 65 import { hilog } from '@kit.PerformanceAnalysisKit'; 66 import { BusinessError } from '@kit.BasicServicesKit'; 67 68 const TAG: string = 'JsCardFormAbility'; 69 const DOMAIN_NUMBER: number = 0xFF00; 70 ``` 71 722. Implement the FormExtension lifecycle callbacks in **EntryFormAbility.ets**. 73 74 ```ts 75 export default class EntryFormAbility extends FormExtensionAbility { 76 onAddForm(want: Want): formBindingData.FormBindingData { 77 hilog.info(DOMAIN_NUMBER, TAG, '[EntryFormAbility] onAddForm'); 78 // Called when the widget is created. The widget provider should return the widget data binding class. 79 let obj: Record<string, string> = { 80 'title': 'titleOnCreate', 81 'detail': 'detailOnCreate' 82 }; 83 let formData: formBindingData.FormBindingData = formBindingData.createFormBindingData(obj); 84 return formData; 85 } 86 onCastToNormalForm(formId: string): void { 87 // Called when a temporary widget is being converted into a normal one. The widget provider should respond to the conversion. 88 hilog.info(DOMAIN_NUMBER, TAG, '[EntryFormAbility] onCastToNormalForm'); 89 } 90 onUpdateForm(formId: string): void { 91 // Override this method to support scheduled updates, periodic updates, or updates requested by the widget host. 92 hilog.info(DOMAIN_NUMBER, TAG, '[EntryFormAbility] onUpdateForm'); 93 let obj: Record<string, string> = { 94 'title': 'titleOnUpdate', 95 'detail': 'detailOnUpdate' 96 }; 97 let formData: formBindingData.FormBindingData = formBindingData.createFormBindingData(obj); 98 formProvider.updateForm(formId, formData).catch((error: BusinessError) => { 99 hilog.info(DOMAIN_NUMBER, TAG, '[EntryFormAbility] updateForm, error:' + JSON.stringify(error)); 100 }); 101 } 102 onChangeFormVisibility(newStatus: Record<string, number>): void { 103 // Called when the widget host initiates an event about visibility changes. The widget provider should do something to respond to the notification. This callback takes effect only for system applications. 104 hilog.info(DOMAIN_NUMBER, TAG, '[EntryFormAbility] onChangeFormVisibility'); 105 //... 106 } 107 onFormEvent(formId: string, message: string): void { 108 // If the widget supports event triggering, override this method and implement the trigger. 109 hilog.info(DOMAIN_NUMBER, TAG, '[EntryFormAbility] onFormEvent'); 110 } 111 onRemoveForm(formId: string): void { 112 // Delete widget data. 113 hilog.info(DOMAIN_NUMBER, TAG, '[EntryFormAbility] onRemoveForm'); 114 //... 115 } 116 onAcquireFormState(want: Want): formInfo.FormState { 117 return formInfo.FormState.READY; 118 } 119 } 120 ``` 121 122> **NOTE** 123> 124> FormExtensionAbility cannot reside in the background. Therefore, continuous tasks cannot be processed in the widget lifecycle callbacks. 125 126 127### Configuring the Widget Configuration Files 128 1291. Configure ExtensionAbility information under **extensionAbilities** in the [module.json5 file](../quick-start/module-configuration-file.md). For a FormExtensionAbility, you must specify **metadata**. Specifically, set **name** to **ohos.extension.form** (fixed), and set **resource** to the index of the widget configuration information. 130 Example configuration: 131 132 133 ```json 134 { 135 "module": { 136 // ... 137 "extensionAbilities": [ 138 { 139 "name": "JsCardFormAbility", 140 "srcEntry": "./ets/jscardformability/JsCardFormAbility.ts", 141 "description": "$string:JSCardFormAbility_desc", 142 "label": "$string:JSCardFormAbility_label", 143 "type": "form", 144 "metadata": [ 145 { 146 "name": "ohos.extension.form", 147 "resource": "$profile:form_jscard_config" 148 } 149 ] 150 } 151 ] 152 } 153 } 154 ``` 155 1562. Configure the widget configuration information. In the **metadata** configuration item of FormExtensionAbility, you can specify the resource index of specific configuration information of the widget. For example, if **resource** is set to **$profile:form_config**, **form_config.json** in the **resources/base/profile/** directory of the development view is used as the profile configuration file of the widget. The following table describes the internal structure of the profile configuration file. 157 158 **Table 1** Widget profile configuration file 159 160 | Field| Description| Data Type| Default Value Allowed| 161 | -------- | -------- | -------- | -------- | 162 | name | Class name of the widget. The value is a string with a maximum of 127 bytes.| String| No| 163 | description | Description of the widget. The value can be a string or a resource index to descriptions in multiple languages. The value is a string with a maximum of 255 bytes.| String| Yes (initial value: left empty)| 164 | src | Full path of the UI code corresponding to the widget.| String| No| 165 | window | Window-related configurations.| Object| Yes| 166 | isDefault | Whether the widget is a default one. Each UIAbility has only one default widget.<br>- **true**: The widget is the default one.<br>- **false**: The widget is not the default one.| Boolean| No| 167 | colorMode | Color mode of the widget.<br>- **auto**: auto-adaptive color mode<br>- **dark**: dark color mode<br>- **light**: light color mode| String| Yes (initial value: **auto**)| 168 | supportDimensions | Grid styles supported by the widget.<br>- **1 * 2**: indicates a grid with one row and two columns.<br>- **2 * 2**: indicates a grid with two rows and two columns.<br>- **2 * 4**: indicates a grid with two rows and four columns.<br>- **4 * 4**: indicates a grid with four rows and four columns.| String array| No| 169 | defaultDimension | Default grid style of the widget. The value must be available in the **supportDimensions** array of the widget.| String| No| 170 | updateEnabled | Whether the widget can be updated periodically.<br>- **true**: The widget can be updated at a specified interval (**updateDuration**) or at the scheduled time (**scheduledUpdateTime**). **updateDuration** takes precedence over **scheduledUpdateTime**.<br>- **false**: The widget cannot be updated periodically.| Boolean| No| 171 | scheduledUpdateTime | Scheduled time to update the widget. The value is in 24-hour format and accurate to minute.<br>**updateDuration** takes precedence over **scheduledUpdateTime**. If both are specified, the value specified by **updateDuration** is used.| String| Yes (initial value: **0:0**)| 172 | updateDuration | Interval to update the widget. The value is a natural number, in the unit of 30 minutes.<br>If the value is **0**, this field does not take effect.<br>If the value is a positive integer *N*, the interval is calculated by multiplying *N* and 30 minutes.<br>**updateDuration** takes precedence over **scheduledUpdateTime**. If both are specified, the value specified by **updateDuration** is used.| Number| Yes (initial value: **0**)| 173 | formConfigAbility | Link to a specific page of the application. The value is a URI.| String| Yes (initial value: left empty)| 174 | formVisibleNotify | Whether the widget is allowed to use the widget visibility notification.| String| Yes (initial value: left empty)| 175 | metaData | Metadata of the widget. This field contains the array of the **customizeData** field.| Object| Yes (initial value: left empty)| 176 177 Example configuration: 178 179 180 ```json 181 { 182 "forms": [ 183 { 184 "name": "WidgetJS", 185 "description": "$string:JSCardEntryAbility_desc", 186 "src": "./js/WidgetJS/pages/index/index", 187 "window": { 188 "designWidth": 720, 189 "autoDesignWidth": true 190 }, 191 "colorMode": "auto", 192 "isDefault": true, 193 "updateEnabled": true, 194 "scheduledUpdateTime": "10:30", 195 "updateDuration": 1, 196 "defaultDimension": "2*2", 197 "supportDimensions": [ 198 "2*2" 199 ] 200 } 201 ] 202 } 203 ``` 204 205 206### Persistently Storing Widget Data 207 208A widget provider is usually started when it is needed to provide information about a widget. The Widget Manager supports multi-instance management and uses the widget ID to identify an instance. If the widget provider supports widget data modification, it must persistently store the data based on the widget ID, so that it can access the data of the target widget when obtaining, updating, or starting a widget. 209 210 211```ts 212import { common, Want } from '@kit.AbilityKit'; 213import { hilog } from '@kit.PerformanceAnalysisKit'; 214import { formBindingData, FormExtensionAbility } from '@kit.FormKit'; 215import { BusinessError } from '@kit.BasicServicesKit'; 216import { preferences } from '@kit.ArkData'; 217 218const TAG: string = 'JsCardFormAbility'; 219const DATA_STORAGE_PATH: string = '/data/storage/el2/base/haps/form_store'; 220const DOMAIN_NUMBER: number = 0xFF00; 221 222let storeFormInfo = async (formId: string, formName: string, tempFlag: boolean, context: common.FormExtensionContext): Promise<void> => { 223 // Only the widget ID (formId), widget name (formName), and whether the widget is a temporary one (tempFlag) are persistently stored. 224 let formInfo: Record<string, string | boolean | number> = { 225 'formName': formName, 226 'tempFlag': tempFlag, 227 'updateCount': 0 228 }; 229 try { 230 const storage: preferences.Preferences = await preferences.getPreferences(context, DATA_STORAGE_PATH); 231 // put form info 232 await storage.put(formId, JSON.stringify(formInfo)); 233 hilog.info(DOMAIN_NUMBER, TAG, `[EntryFormAbility] storeFormInfo, put form info successfully, formId: ${formId}`); 234 await storage.flush(); 235 } catch (err) { 236 hilog.error(DOMAIN_NUMBER, TAG, `[EntryFormAbility] failed to storeFormInfo, err: ${JSON.stringify(err as BusinessError)}`); 237 } 238} 239 240export default class JsCardFormAbility extends FormExtensionAbility { 241 onAddForm(want: Want): formBindingData.FormBindingData { 242 hilog.info(DOMAIN_NUMBER, TAG, '[JsCardFormAbility] onAddForm'); 243 244 if (want.parameters) { 245 let formId = JSON.stringify(want.parameters['ohos.extra.param.key.form_identity']); 246 let formName = JSON.stringify(want.parameters['ohos.extra.param.key.form_name']); 247 let tempFlag = want.parameters['ohos.extra.param.key.form_temporary'] as boolean; 248 // Persistently store widget data for subsequent use, such as instance acquisition and update. 249 // Implement this API based on project requirements. 250 storeFormInfo(formId, formName, tempFlag, this.context); 251 } 252 253 let obj: Record<string, string> = { 254 'title': 'titleOnCreate', 255 'detail': 'detailOnCreate' 256 }; 257 let formData: formBindingData.FormBindingData = formBindingData.createFormBindingData(obj); 258 return formData; 259 } 260} 261``` 262 263You should override **onRemoveForm** to implement widget data deletion. 264 265 266```ts 267import { common } from '@kit.AbilityKit'; 268import { hilog } from '@kit.PerformanceAnalysisKit'; 269import { FormExtensionAbility } from '@kit.FormKit'; 270import { BusinessError } from '@kit.BasicServicesKit'; 271import { preferences } from '@kit.ArkData'; 272 273const TAG: string = 'JsCardFormAbility'; 274const DATA_STORAGE_PATH: string = '/data/storage/el2/base/haps/form_store'; 275const DOMAIN_NUMBER: number = 0xFF00; 276 277let deleteFormInfo = async (formId: string, context: common.FormExtensionContext): Promise<void> => { 278 try { 279 const storage: preferences.Preferences = await preferences.getPreferences(context, DATA_STORAGE_PATH); 280 // Delete the widget information. 281 await storage.delete(formId); 282 hilog.info(DOMAIN_NUMBER, TAG, `[EntryFormAbility] deleteFormInfo, del form info successfully, formId: ${formId}`); 283 await storage.flush(); 284 } catch (err) { 285 hilog.error(DOMAIN_NUMBER, TAG, `[EntryFormAbility] failed to deleteFormInfo, err: ${JSON.stringify(err as BusinessError)}`); 286 }; 287}; 288 289export default class JsCardFormAbility extends FormExtensionAbility { 290 onRemoveForm(formId: string): void { 291 // Delete widget data. 292 hilog.info(DOMAIN_NUMBER, TAG, '[EntryFormAbility] onRemoveForm'); 293 // Delete the persistent widget instance data. 294 // Implement this API based on project requirements. 295 deleteFormInfo(formId, this.context); 296 } 297} 298``` 299 300For details about how to implement persistent data storage, see [Application Data Persistence](../database/app-data-persistence-overview.md). 301 302The **Want** object passed in by the widget host to the widget provider contains a flag that specifies whether the requested widget is normal or temporary. 303 304- Normal widget: a widget persistently used by the widget host 305 306- Temporary widget: a widget temporarily used by the widget host 307 308Data of a temporary widget will be deleted on the Widget Manager if the widget framework is killed and restarted. The widget provider, however, is not notified of the deletion and still keeps the data. Therefore, the widget provider needs to clear the data of temporary widgets proactively if the data has been kept for a long period of time. If the widget host has converted a temporary widget into a normal one, the widget provider should change the widget data from temporary storage to persistent storage. Otherwise, the widget data may be deleted by mistake. 309 310 311### Updating Widget Data 312 313When an application initiates a scheduled or periodic update, the application obtains the latest data and calls **updateForm()** to update the widget. 314 315 316```ts 317import { hilog } from '@kit.PerformanceAnalysisKit'; 318import { formBindingData, FormExtensionAbility, formProvider } from '@kit.FormKit'; 319import { BusinessError } from '@kit.BasicServicesKit'; 320 321const TAG: string = 'JsCardFormAbility'; 322const DOMAIN_NUMBER: number = 0xFF00; 323 324export default class EntryFormAbility extends FormExtensionAbility { 325 onUpdateForm(formId: string): void { 326 // Override this method to support scheduled updates, periodic updates, or updates requested by the widget host. 327 hilog.info(DOMAIN_NUMBER, TAG, '[EntryFormAbility] onUpdateForm'); 328 let obj: Record<string, string> = { 329 'title': 'titleOnUpdate', 330 'detail': 'detailOnUpdate' 331 }; 332 let formData: formBindingData.FormBindingData = formBindingData.createFormBindingData(obj); 333 formProvider.updateForm(formId, formData).catch((error: BusinessError) => { 334 hilog.info(DOMAIN_NUMBER, TAG, '[EntryFormAbility] updateForm, error:' + JSON.stringify(error)); 335 }); 336 } 337} 338``` 339 340 341### Developing the Widget UI Page 342 343You can use the web-like paradigm (HML+CSS+JSON) to develop JS widget pages. This section describes how to develop a page shown below. 344 345 346 347- HML: uses web-like paradigm components to describe the widget page information. 348 349 350 ```html 351 <div class="container"> 352 <stack> 353 <div class="container-img"> 354 <image src="/common/widget.png" class="bg-img"></image> 355 </div> 356 <div class="container-inner"> 357 <text class="title">{{title}}</text> 358 <text class="detail_text" onclick="routerEvent">{{detail}}</text> 359 </div> 360 </stack> 361 </div> 362 ``` 363 364- CSS: defines style information about the web-like paradigm components in HML. 365 366 367 ```css 368 .container { 369 flex-direction: column; 370 justify-content: center; 371 align-items: center; 372 } 373 374 .bg-img { 375 flex-shrink: 0; 376 height: 100%; 377 } 378 379 .container-inner { 380 flex-direction: column; 381 justify-content: flex-end; 382 align-items: flex-start; 383 height: 100%; 384 width: 100%; 385 padding: 12px; 386 } 387 388 .title { 389 font-size: 19px; 390 font-weight: bold; 391 color: white; 392 text-overflow: ellipsis; 393 max-lines: 1; 394 } 395 396 .detail_text { 397 font-size: 16px; 398 color: white; 399 opacity: 0.66; 400 text-overflow: ellipsis; 401 max-lines: 1; 402 margin-top: 6px; 403 } 404 ``` 405 406- JSON: defines data and event interaction on the widget UI page. 407 408 409 ```json 410 { 411 "data": { 412 "title": "TitleDefault", 413 "detail": "TextDefault" 414 }, 415 "actions": { 416 "routerEvent": { 417 "action": "router", 418 "abilityName": "EntryAbility", 419 "params": { 420 "message": "add detail" 421 } 422 } 423 } 424 } 425 ``` 426 427 428### Developing Widget Events 429 430You can set router and message events for components on a widget. The router event applies to UIAbility redirection, and the message event applies to custom click events. 431 432The key steps are as follows: 433 4341. Set the **onclick** field in the HML file to **routerEvent** or **messageEvent**, depending on the **actions** settings in the JSON file. 435 4362. Set the router event. 437 438 - **action**: **"router"**, which indicates a router event. 439 - **abilityName**: name of the UIAbility to redirect to (PageAbility component in the FA model and UIAbility component in the stage model). For example, the default UIAbility name of the stage model created by DevEco Studio is EntryAbility. 440 - **params**: custom parameters passed to the target UIAbility. Set them as required. The value can be obtained from **parameters** in **want** used for starting the target UIAbility. For example, in the lifecycle function **onCreate** of the MainAbility in the stage model, you can obtain **want** and its **parameters** field. 441 4423. Set the message event. 443 444 - **action**: **"message"**, which indicates a message event. 445 - **params**: custom parameters of the message event. Set them as required. The value can be obtained from **message** in the widget lifecycle function **onFormEvent()**. 446 447The following are examples: 448 449- HML file: 450 451 452 ```html 453 <div class="container"> 454 <stack> 455 <div class="container-img"> 456 <image src="/common/CardWebImg.png" class="bg-img"></image> 457 <image src="/common/CardWebImgMatrix.png" 458 class="bottom-img"/> 459 </div> 460 <div class="container-inner"> 461 <text class="title" onclick="routerEvent">{{ title }}</text> 462 <text class="detail_text" onclick="messageEvent">{{ detail }}</text> 463 </div> 464 </stack> 465 </div> 466 ``` 467 468- CSS file: 469 470 471 ```css 472 .container { 473 flex-direction: column; 474 justify-content: center; 475 align-items: center; 476 } 477 478 .bg-img { 479 flex-shrink: 0; 480 height: 100%; 481 z-index: 1; 482 } 483 484 .bottom-img { 485 position: absolute; 486 width: 150px; 487 height: 56px; 488 top: 63%; 489 background-color: rgba(216, 216, 216, 0.15); 490 filter: blur(20px); 491 z-index: 2; 492 } 493 494 .container-inner { 495 flex-direction: column; 496 justify-content: flex-end; 497 align-items: flex-start; 498 height: 100%; 499 width: 100%; 500 padding: 12px; 501 } 502 503 .title { 504 font-family: HarmonyHeiTi-Medium; 505 font-size: 14px; 506 color: rgba(255, 255, 255, 0.90); 507 letter-spacing: 0.6px; 508 font-weight: 500; 509 width: 100%; 510 text-overflow: ellipsis; 511 max-lines: 1; 512 } 513 514 .detail_text { 515 ffont-family: HarmonyHeiTi; 516 font-size: 12px; 517 color: rgba(255, 255, 255, 0.60); 518 letter-spacing: 0.51px; 519 font-weight: 400; 520 text-overflow: ellipsis; 521 max-lines: 1; 522 margin-top: 6px; 523 width: 100%; 524 } 525 ``` 526 527- JSON file: 528 529 530 ```json 531 { 532 "data": { 533 "title": "TitleDefault", 534 "detail": "TextDefault" 535 }, 536 "actions": { 537 "routerEvent": { 538 "action": "router", 539 "abilityName": "JSCardEntryAbility", 540 "params": { 541 "info": "router info", 542 "message": "router message" 543 } 544 }, 545 "messageEvent": { 546 "action": "message", 547 "params": { 548 "detail": "message detail" 549 } 550 } 551 } 552 } 553 ``` 554 555 > **NOTE** 556 > 557 > **JSON Value** in **data** supports multi-level nested data. When updating data, ensure that complete data is carried. 558 559 Assume that a widget is displaying the course information of Mr. Zhang on July 18, as shown in the following code snippet. 560 ```ts 561 "data": { 562 "Day": "07.18", 563 "teacher": { 564 "name": "Mr.Zhang", 565 "course": "Math" 566 } 567 } 568 ``` 569 To update the widget content to the course information of Mr. Li on July 18, you must pass the complete data as follows, instead of only a single date item such as **name** or **course**: 570 ```ts 571 "teacher": { 572 "name": "Mr.Li", 573 "course": "English" 574 } 575 ``` 576 577 578- Receive the router event in UIAbility and obtain parameters. 579 580 581 ```ts 582 import UIAbility from '@ohos.app.ability.UIAbility'; 583 import AbilityConstant from '@ohos.app.ability.AbilityConstant'; 584 import Want from '@ohos.app.ability.Want'; 585 import hilog from '@ohos.hilog'; 586 587 const TAG: string = 'EtsCardEntryAbility'; 588 const DOMAIN_NUMBER: number = 0xFF00; 589 590 export default class EtsCardEntryAbility extends UIAbility { 591 onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void { 592 if (want.parameters) { 593 let params: Record<string, Object> = JSON.parse(JSON.stringify(want.parameters.params)); 594 // Obtain the info parameter passed in the router event. 595 if (params.info === 'router info') { 596 // Execute the service logic. 597 hilog.info(DOMAIN_NUMBER, TAG, `router info: ${params.info}`); 598 } 599 // Obtain the message parameter passed in the router event. 600 if (params.message === 'router message') { 601 // Execute the service logic. 602 hilog.info(DOMAIN_NUMBER, TAG, `router message: ${params.message}`); 603 } 604 } 605 } 606 }; 607 ``` 608 609- Receive the message event in FormExtensionAbility and obtain parameters. 610 611 612 ```ts 613 import FormExtension from '@ohos.app.form.FormExtensionAbility'; 614 import hilog from '@ohos.hilog'; 615 616 const TAG: string = 'FormAbility'; 617 const DOMAIN_NUMBER: number = 0xFF00; 618 619 export default class FormAbility extends FormExtension { 620 onFormEvent(formId: string, message: string): void { 621 // If the widget supports event triggering, override this method and implement the trigger. 622 hilog.info(DOMAIN_NUMBER, TAG, '[EntryFormAbility] onFormEvent'); 623 // Obtain the detail parameter passed in the message event. 624 let msg: Record<string, string> = JSON.parse(message); 625 if (msg.detail === 'message detail') { 626 // Execute the service logic. 627 hilog.info(DOMAIN_NUMBER, TAG, 'message info:' + msg.detail); 628 } 629 } 630 }; 631 ``` 632