• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# FormExtensionAbility(服务卡片)
2
3
4## 卡片概述
5
6FormExtensionAbility就是服务卡片扩展组件(以下简称“卡片”),是一种界面展示形式,可以将应用的重要信息或操作前置到卡片,以达到服务直达,减少体验层级的目的。
7
8卡片常用于嵌入到其他应用(当前只支持系统应用)中作为其界面的一部分显示,并支持拉起页面、发送消息等基础的交互功能。
9
10卡片的基本概念:
11
12- 卡片使用方:显示卡片内容的宿主应用,控制卡片在宿主中展示的位置。
13
14- 卡片管理服务:用于管理系统中所添加卡片的常驻代理服务,包括卡片对象的管理与使用,以及卡片周期性刷新等。
15
16- 卡片提供方:提供卡片显示内容原子化服务,控制卡片的显示内容、控件布局以及控件点击事件。
17
18
19## 运作机制
20
21卡片框架的运作机制如图1所示。
22
23  **图1** 卡片框架运作机制(Stage模型)  
24![form-extension](figures/form-extension.png)
25
26卡片使用方包含以下模块:
27
28- 卡片使用:包含卡片的创建、删除、请求更新等操作。
29
30- 通信适配层:由OpenHarmony SDK提供,负责与卡片管理服务通信,用于将卡片的相关操作到卡片管理服务。
31
32卡片管理服务包含以下模块:
33
34- 周期性刷新:在卡片添加后,根据卡片的刷新策略启动定时任务周期性触发卡片的刷新。
35
36- 卡片缓存管理:在卡片添加到卡片管理服务后,对卡片的视图信息进行缓存,以便下次获取卡片时可以直接返回缓存数据,降低时延。
37
38- 卡片生命周期管理:对于卡片切换到后台或者被遮挡时,暂停卡片的刷新;以及卡片的升级/卸载场景下对卡片数据的更新和清理。
39
40- 卡片使用方对象管理:对卡片使用方的RPC对象进行管理,用于使用方请求进行校验以及对卡片更新后的回调处理。
41
42- 通信适配层:负责与卡片使用方和提供方进行RPC通信。
43
44卡片提供方包含以下模块:
45
46- 卡片服务:由卡片提供方开发者实现,开发者实现生命周期处理创建卡片、更新卡片以及删除卡片等请求,提供相应的卡片服务。
47
48- 卡片提供方实例管理模块:由卡片提供方开发者实现,负责对卡片管理服务分配的卡片实例进行持久化管理。
49
50- 通信适配层:由OpenHarmony SDK提供,负责与卡片管理服务通信,用于将卡片的更新数据主动推送到卡片管理服务。
51
52> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
53> 实际开发时只需要作为卡片提供方进行卡片内容的开发,卡片使用方和卡片管理服务由系统自动处理。
54
55
56## 接口说明
57
58FormExtensionAbility类拥有如下API接口,具体的API介绍详见[接口文档](../reference/apis/js-apis-app-form-formExtensionAbility.md)。
59
60| 接口名 | 描述 |
61| -------- | -------- |
62| onAddForm(want: Want): formBindingData.FormBindingData | 卡片提供方接收创建卡片的通知接口。 |
63| onCastToNormalForm(formId: string): void | 卡片提供方接收临时卡片转常态卡片的通知接口。 |
64| onUpdateForm(formId: string): void | 卡片提供方接收更新卡片的通知接口。 |
65| onChangeFormVisibility(newStatus: { [key: string]: number }): void | 卡片提供方接收修改可见性的通知接口。 |
66| onFormEvent(formId: string, message: string): void | 卡片提供方接收处理卡片事件的通知接口。 |
67| onRemoveForm(formId: string): void | 卡片提供方接收销毁卡片的通知接口。 |
68| onConfigurationUpdate(config: Configuration): void | 当系统配置更新时调用。 |
69| onShareForm?(formId: string): { [key: string]: any } | 卡片提供方接收卡片分享的通知接口。 |
70
71FormExtensionAbility类还拥有成员context,为FormExtensionContext类,具体的API介绍详见[接口文档](../reference/apis/js-apis-inner-application-formExtensionContext.md)。
72
73| 接口名 | 描述 |
74| -------- | -------- |
75| startAbility(want: Want, callback: AsyncCallback<void>): void | 回调形式拉起一个卡片所属应用的UIAbility(系统接口,三方应用不支持调用,需申请后台拉起权限)。 |
76| startAbility(want: Want): Promise<void> | Promise形式拉起一个卡片所属应用的UIAbility(系统接口,三方应用不支持调用,需申请后台拉起权限)。 |
77
78formProvider类有如下API接口,具体的API介绍详见[接口文档](../reference/apis/js-apis-app-form-formProvider.md)。
79
80| 接口名 | 描述 |
81| -------- | -------- |
82| setFormNextRefreshTime(formId: string, minute: number, callback: AsyncCallback<void>): void; | 设置指定卡片的下一次更新时间。 |
83| setFormNextRefreshTime(formId: string, minute: number): Promise<void>; | 设置指定卡片的下一次更新时间,以promise方式返回。 |
84| updateForm(formId: string, formBindingData: FormBindingData, callback: AsyncCallback<void>): void; | 更新指定的卡片。 |
85| updateForm(formId: string, formBindingData: FormBindingData): Promise<void>; | 更新指定的卡片,以promise方式返回。 |
86
87formBindingData类有如下API接口,具体的API介绍详见[接口文档](../reference/apis/js-apis-app-form-formBindingData.md)。
88
89| 接口名 | 描述 |
90| -------- | -------- |
91| createFormBindingData(obj?: Object \| string): FormBindingData | 创建一个FormBindingData对象。 |
92
93
94## 开发步骤
95
96Stage卡片开发,即基于[Stage模型](stage-model-development-overview.md)的卡片提供方开发,主要涉及如下关键步骤:
97
98- [创建卡片FormExtensionAbility](#创建卡片formextensionability):卡片生命周期回调函数FormExtensionAbility开发。
99
100- [配置卡片配置文件](#配置卡片配置文件):配置应用配置文件module.json5和profile配置文件。
101
102- [卡片数据交互](#卡片数据交互):对卡片信息进行持久化管理。
103
104- [卡片数据交互](#卡片数据交互):通过updateForm更新卡片显示的信息。
105
106- [开发卡片页面](#开发卡片页面):使用HML+CSS+JSON开发JS卡片页面。
107
108- [开发卡片事件](#开发卡片事件):为卡片添加router事件和message事件。
109
110
111### 创建卡片FormExtensionAbility
112
113创建Stage模型的卡片,需实现FormExtensionAbility生命周期接口。先参考[DevEco Studio服务卡片开发指南](https://developer.harmonyos.com/cn/docs/documentation/doc-guides/ohos-development-service-widget-0000001263280425)生成服务卡片模板。
114
1151. 在EntryFormAbility.ts中,导入相关模块。
116
117   ```ts
118   import FormExtension from '@ohos.app.form.FormExtensionAbility';
119   import formBindingData from '@ohos.app.form.formBindingData';
120   import formInfo from '@ohos.app.form.formInfo';
121   import formProvider from '@ohos.app.form.formProvider';
122   import dataStorage from '@ohos.data.storage';
123   ```
124
1252. 在EntryFormAbility.ts中,实现FormExtension生命周期接口。
126
127   ```ts
128   export default class EntryFormAbility extends FormExtension {
129       onAddForm(want) {
130           console.info('[EntryFormAbility] onAddForm');
131           // 使用方创建卡片时触发,提供方需要返回卡片数据绑定类
132           let obj = {
133               "title": "titleOnCreate",
134               "detail": "detailOnCreate"
135           };
136           let formData = formBindingData.createFormBindingData(obj);
137           return formData;
138       }
139       onCastToNormalForm(formId) {
140           // 使用方将临时卡片转换为常态卡片触发,提供方需要做相应的处理
141           console.info('[EntryFormAbility] onCastToNormalForm');
142       }
143       onUpdateForm(formId) {
144           // 若卡片支持定时更新/定点更新/卡片使用方主动请求更新功能,则提供方需要重写该方法以支持数据更新
145           console.info('[EntryFormAbility] onUpdateForm');
146           let obj = {
147               "title": "titleOnUpdate",
148               "detail": "detailOnUpdate"
149           };
150           let formData = formBindingData.createFormBindingData(obj);
151           formProvider.updateForm(formId, formData).catch((error) => {
152               console.info('[EntryFormAbility] updateForm, error:' + JSON.stringify(error));
153           });
154       }
155       onChangeFormVisibility(newStatus) {
156           // 使用方发起可见或者不可见通知触发,提供方需要做相应的处理,仅系统应用生效
157           console.info('[EntryFormAbility] onChangeFormVisibility');
158       }
159       onFormEvent(formId, message) {
160           // 若卡片支持触发事件,则需要重写该方法并实现对事件的触发
161           console.info('[EntryFormAbility] onFormEvent');
162       }
163       onRemoveForm(formId) {
164           // 删除卡片实例数据
165           console.info('[EntryFormAbility] onRemoveForm');
166       }
167       onConfigurationUpdate(config) {
168           console.info('[EntryFormAbility] nConfigurationUpdate, config:' + JSON.stringify(config));
169       }
170       onAcquireFormState(want) {
171           return formInfo.FormState.READY;
172       }
173   }
174   ```
175
176> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
177> FormExtensionAbility不能常驻后台,即在卡片生命周期回调函数中无法处理长时间的任务。
178
179### 配置卡片配置文件
180
1811. 卡片需要在[module.json5配置文件](../quick-start/module-configuration-file.md)中的extensionAbilities标签下,配置ExtensionAbility相关信息。FormExtensionAbility需要填写metadata元信息标签,其中键名称为固定字符串"ohos.extension.form",资源为卡片的具体配置信息的索引。
182   配置示例如下:
183
184
185   ```json
186   {
187     "module": {
188       // ...
189       "extensionAbilities": [
190         {
191           "name": "EntryFormAbility",
192           "srcEntrance": "./ets/entryformability/EntryFormAbility.ts",
193           "label": "$string:EntryFormAbility_label",
194           "description": "$string:EntryFormAbility_desc",
195           "type": "form",
196           "metadata": [
197             {
198               "name": "ohos.extension.form",
199               "resource": "$profile:form_config"
200             }
201           ]
202         }
203       ]
204     }
205   }
206   ```
207
2082. 卡片的具体配置信息。在上述FormExtensionAbility的元信息("metadata"配置项)中,可以指定卡片具体配置信息的资源索引。例如当resource指定为$profile:form_config时,会使用开发视图的resources/base/profile/目录下的form_config.json作为卡片profile配置文件。内部字段结构说明如下表所示。
209     **表1** 卡片profile配置文件
210
211   | 属性名称 | 含义 | 数据类型 | 是否可缺省 |
212   | -------- | -------- | -------- | -------- |
213   | name | 表示卡片的类名,字符串最大长度为127字节。 | 字符串 | 否 |
214   | description | 表示卡片的描述。取值可以是描述性内容,也可以是对描述性内容的资源索引,以支持多语言。字符串最大长度为255字节。 | 字符串 | 可缺省,缺省为空。 |
215   | src | 表示卡片对应的UI代码的完整路径。 | 字符串 | 否 |
216   | window | 用于定义与显示窗口相关的配置。 | 对象 | 可缺省 |
217   | isDefault | 表示该卡片是否为默认卡片,每个Ability有且只有一个默认卡片。<br/>true:默认卡片。<br/>false:非默认卡片。 | 布尔值 | 否 |
218   | colorMode | 表示卡片的主题样式,取值范围如下:<br/>auto:自适应。<br/>dark:深色主题。<br/>light:浅色主题。 | 字符串 | 可缺省,缺省值为“auto”。 |
219   | supportDimensions | 表示卡片支持的外观规格,取值范围:<br/>1&nbsp;\*&nbsp;2:表示1行2列的二宫格。<br/>2&nbsp;\*&nbsp;2:表示2行2列的四宫格。<br/>2&nbsp;\*&nbsp;4:表示2行4列的八宫格。<br/>4&nbsp;\*&nbsp;4:表示4行4列的十六宫格。 | 字符串数组 | 否 |
220   | defaultDimension | 表示卡片的默认外观规格,取值必须在该卡片supportDimensions配置的列表中。 | 字符串 | 否 |
221   | updateEnabled | 表示卡片是否支持周期性刷新,取值范围:<br/>true:表示支持周期性刷新,可以在定时刷新(updateDuration)和定点刷新(scheduledUpdateTime)两种方式任选其一,优先选择定时刷新。<br/>false:表示不支持周期性刷新。 | 布尔类型 | 否 |
222   | scheduledUpdateTime | 表示卡片的定点刷新的时刻,采用24小时制,精确到分钟。<br/>updateDuration参数优先级高于scheduledUpdateTime,两者同时配置时,以updateDuration配置的刷新时间为准。 | 字符串 | 可缺省,缺省值为“0:0”。 |
223   | updateDuration | 表示卡片定时刷新的更新周期,单位为30分钟,取值为自然数。<br/>当取值为0时,表示该参数不生效。<br/>当取值为正整数N时,表示刷新周期为30\*N分钟。<br/>updateDuration参数优先级高于scheduledUpdateTime,两者同时配置时,以updateDuration配置的刷新时间为准。 | 数值 | 可缺省,缺省值为“0”。 |
224   | formConfigAbility | 表示卡片的配置跳转链接,采用URI格式。 | 字符串 | 可缺省,缺省值为空。 |
225   | formVisibleNotify | 标识是否允许卡片使用卡片可见性通知。 | 字符串 | 可缺省,缺省值为空。 |
226   | metaData | 表示卡片的自定义信息,包含customizeData数组标签。 | 对象 | 可缺省,缺省值为空。 |
227
228     配置示例如下:
229
230   ```json
231   {
232     "forms": [
233       {
234         "name": "widget",
235         "description": "This is a service widget.",
236         "src": "./js/widget/pages/index/index",
237         "window": {
238           "designWidth": 720,
239           "autoDesignWidth": true
240         },
241         "colorMode": "auto",
242         "isDefault": true,
243         "updateEnabled": true,
244         "scheduledUpdateTime": "10:30",
245         "updateDuration": 1,
246         "defaultDimension": "2*2",
247         "supportDimensions": [
248           "2*2"
249         ]
250       }
251     ]
252   }
253   ```
254
255
256### 卡片信息的持久化
257
258因大部分卡片提供方都不是常驻服务,只有在需要使用时才会被拉起获取卡片信息,且卡片管理服务支持对卡片进行多实例管理,卡片ID对应实例ID,因此若卡片提供方支持对卡片数据进行配置,则需要对卡片的业务数据按照卡片ID进行持久化管理,以便在后续获取、更新以及拉起时能获取到正确的卡片业务数据。
259
260
261```ts
262const DATA_STORAGE_PATH = "/data/storage/el2/base/haps/form_store";
263async function storeFormInfo(formId: string, formName: string, tempFlag: boolean) {
264    // 此处仅对卡片ID:formId,卡片名:formName和是否为临时卡片:tempFlag进行了持久化
265    let formInfo = {
266        "formName": formName,
267        "tempFlag": tempFlag,
268        "updateCount": 0
269    };
270    try {
271        const storage = await dataStorage.getStorage(DATA_STORAGE_PATH);
272        // put form info
273        await storage.put(formId, JSON.stringify(formInfo));
274        console.info(`[EntryFormAbility] storeFormInfo, put form info successfully, formId: ${formId}`);
275        await storage.flush();
276    } catch (err) {
277        console.error(`[EntryFormAbility] failed to storeFormInfo, err: ${JSON.stringify(err)}`);
278    }
279}
280
281export default class EntryFormAbility extends FormExtension {
282    // ...
283    onAddForm(want) {
284        console.info('[EntryFormAbility] onAddForm');
285
286        let formId = want.parameters["ohos.extra.param.key.form_identity"];
287        let formName = want.parameters["ohos.extra.param.key.form_name"];
288        let tempFlag = want.parameters["ohos.extra.param.key.form_temporary"];
289        // 将创建的卡片信息持久化,以便在下次获取/更新该卡片实例时进行使用
290        // 此接口请根据实际情况实现,具体请参考:FormExtAbility Stage模型卡片实例
291        storeFormInfo(formId, formName, tempFlag);
292
293        let obj = {
294            "title": "titleOnCreate",
295            "detail": "detailOnCreate"
296        };
297        let formData = formBindingData.createFormBindingData(obj);
298        return formData;
299    }
300}
301```
302
303且需要适配onRemoveForm卡片删除通知接口,在其中实现卡片实例数据的删除。
304
305
306```ts
307const DATA_STORAGE_PATH = "/data/storage/el2/base/haps/form_store";
308async function deleteFormInfo(formId: string) {
309    try {
310        const storage = await dataStorage.getStorage(DATA_STORAGE_PATH);
311        // del form info
312        await storage.delete(formId);
313        console.info(`[EntryFormAbility] deleteFormInfo, del form info successfully, formId: ${formId}`);
314        await storage.flush();
315    } catch (err) {
316        console.error(`[EntryFormAbility] failed to deleteFormInfo, err: ${JSON.stringify(err)}`);
317    }
318}
319
320// ...
321
322export default class EntryFormAbility extends FormExtension {
323    // ...
324    onRemoveForm(formId) {
325        console.info('[EntryFormAbility] onRemoveForm');
326        // 删除之前持久化的卡片实例数据
327        // 此接口请根据实际情况实现,具体请参考:FormExtAbility Stage模型卡片实例
328        deleteFormInfo(formId);
329    }
330}
331```
332
333具体的持久化方法可以参考[轻量级数据存储开发指导](../database/database-preference-guidelines.md)。
334
335需要注意的是,卡片使用方在请求卡片时传递给提供方应用的Want数据中存在临时标记字段,表示此次请求的卡片是否为临时卡片:
336
337- 常态卡片:卡片使用方会持久化的卡片;
338
339- 临时卡片:卡片使用方不会持久化的卡片;
340
341由于临时卡片的数据具有非持久化的特殊性,某些场景例如卡片服务框架死亡重启,此时临时卡片数据在卡片管理服务中已经删除,且对应的卡片ID不会通知到提供方,所以卡片提供方需要自己负责清理长时间未删除的临时卡片数据。同时对应的卡片使用方可能会将之前请求的临时卡片转换为常态卡片。如果转换成功,卡片提供方也需要对对应的临时卡片ID进行处理,把卡片提供方记录的临时卡片数据转换为常态卡片数据,防止提供方在清理长时间未删除的临时卡片时,把已经转换为常态卡片的临时卡片信息删除,导致卡片信息丢失。
342
343
344### 卡片数据交互
345
346当卡片应用需要更新数据时(如触发了定时更新或定点更新),卡片应用获取最新数据,并调用updateForm()接口主动触发卡片的更新。
347
348
349```ts
350onUpdateForm(formId) {
351    // 若卡片支持定时更新/定点更新/卡片使用方主动请求更新功能,则提供方需要重写该方法以支持数据更新
352    console.info('[EntryFormAbility] onUpdateForm');
353    let obj = {
354        "title": "titleOnUpdate",
355        "detail": "detailOnUpdate"
356    };
357    let formData = formBindingData.createFormBindingData(obj);
358    // 调用updateForm接口去更新对应的卡片,仅更新入参中携带的数据信息,其他信息保持不变
359    formProvider.updateForm(formId, formData).catch((error) => {
360        console.info('[EntryFormAbility] updateForm, error:' + JSON.stringify(error));
361    });
362}
363```
364
365
366### 开发卡片页面
367
368开发者可以使用类Web范式(HML+CSS+JSON)开发JS卡片页面。生成如下卡片页面,可以这样配置卡片页面文件:
369
370![widget-development-stage](figures/widget-development-stage.png)
371
372> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
373> 当前仅支持JS扩展的类Web开发范式来实现卡片的UI界面。
374
375- HML:使用类Web范式的组件描述卡片的页面信息。
376
377  ```html
378  <div class="container">
379    <stack>
380      <div class="container-img">
381        <image src="/common/widget.png" class="bg-img"></image>
382      </div>
383      <div class="container-inner">
384        <text class="title">{{title}}</text>
385        <text class="detail_text" onclick="routerEvent">{{detail}}</text>
386      </div>
387    </stack>
388  </div>
389  ```
390
391- CSS:HML中类Web范式组件的样式信息。
392
393  ```css
394  .container {
395    flex-direction: column;
396    justify-content: center;
397    align-items: center;
398  }
399
400  .bg-img {
401    flex-shrink: 0;
402    height: 100%;
403  }
404
405  .container-inner {
406    flex-direction: column;
407    justify-content: flex-end;
408    align-items: flex-start;
409    height: 100%;
410    width: 100%;
411    padding: 12px;
412  }
413
414  .title {
415    font-size: 19px;
416    font-weight: bold;
417    color: white;
418    text-overflow: ellipsis;
419    max-lines: 1;
420  }
421
422  .detail_text {
423    font-size: 16px;
424    color: white;
425    opacity: 0.66;
426    text-overflow: ellipsis;
427    max-lines: 1;
428    margin-top: 6px;
429  }
430  ```
431
432- JSON:卡片页面中的数据和事件交互。
433
434  ```json
435  {
436    "data": {
437      "title": "TitleDefault",
438      "detail": "TextDefault"
439    },
440    "actions": {
441      "routerEvent": {
442        "action": "router",
443        "abilityName": "EntryAbility",
444        "params": {
445          "message": "add detail"
446        }
447      }
448    }
449  }
450  ```
451
452
453### 开发卡片事件
454
455卡片支持为组件设置交互事件(action),包括**router**事件和**message**事件,其中router事件用于Ability跳转,message事件用于卡片开发人员自定义点击事件。
456
457关键步骤说明如下:
458
4591. 在HML中为组件设置onclick属性,其值对应到JSON文件的actions字段中。
460
4612. 设置router事件:
462   - action属性值为"router"。
463   - abilityName为跳转目标的Ability名(支持跳转FA模型的PageAbility组件和Stage模型的UIAbility组件),如目前DevEco Studio创建的Stage模型的UIAbility默认名为EntryAbility。
464   - params为传递给跳转目标Ability的自定义参数,可以按需填写。其值可以在目标Ability启动时的want中的parameters里获取。如Stage模型MainAbility的onCreate生命周期里的入参want的parameters字段下获取到配置的参数。
465
4663. 设置message事件:
467   - action属性值为"message"。
468   - params为message事件的用户自定义参数,可以按需填写。其值可以在卡片生命周期函数onFormEvent()中的message里获取。
469
470示例如下。
471
472- HML文件
473
474  ```html
475  <div class="container">
476    <stack>
477      <div class="container-img">
478        <image src="/common/widget.png" class="bg-img"></image>
479      </div>
480      <div class="container-inner">
481        <text class="title" onclick="routerEvent">{{title}}</text>
482        <text class="detail_text" onclick="messageEvent">{{detail}}</text>
483      </div>
484    </stack>
485  </div>
486  ```
487
488- CSS文件
489
490  ```css
491  .container {
492    flex-direction: column;
493    justify-content: center;
494    align-items: center;
495  }
496
497  .bg-img {
498    flex-shrink: 0;
499    height: 100%;
500  }
501
502  .container-inner {
503    flex-direction: column;
504    justify-content: flex-end;
505    align-items: flex-start;
506    height: 100%;
507    width: 100%;
508    padding: 12px;
509  }
510
511  .title {
512    font-size: 19px;
513    font-weight: bold;
514    color: white;
515    text-overflow: ellipsis;
516    max-lines: 1;
517  }
518
519  .detail_text {
520    font-size: 16px;
521    color: white;
522    opacity: 0.66;
523    text-overflow: ellipsis;
524    max-lines: 1;
525    margin-top: 6px;
526  }
527  ```
528
529- JSON文件
530
531  ```json
532  {
533    "data": {
534      "title": "TitleDefault",
535      "detail": "TextDefault"
536    },
537    "actions": {
538      "routerEvent": {
539        "action": "router",
540        "abilityName": "EntryAbility",
541        "params": {
542          "info": "router info",
543          "message": "router message"
544        }
545      },
546      "messageEvent": {
547        "action": "message",
548        "params": {
549          "detail": "message detail"
550        }
551      }
552    }
553  }
554  ```
555
556- 在UIAbility中接收router事件并获取参数
557
558  ```ts
559  import UIAbility from '@ohos.app.ability.UIAbility'
560
561  export default class EntryAbility extends UIAbility {
562      onCreate(want, launchParam) {
563          // 获取router事件中传递的info参数
564          if (want.parameters.info === "router info") {
565              // do something
566              // console.log("router info:" + want.parameters.info)
567          }
568          // 获取router事件中传递的message参数
569          if (want.parameters.message === "router message") {
570              // do something
571              // console.log("router message:" + want.parameters.message)
572          }
573      }
574      // ...
575  };
576  ```
577
578- 在FormExtensionAbility中接收message事件并获取参数
579
580  ```ts
581  import FormExtension from '@ohos.app.form.FormExtensionAbility';
582
583  export default class FormAbility extends FormExtension {
584      // ...
585      onFormEvent(formId, message) {
586          // 获取message事件中传递的detail参数
587          let msg = JSON.parse(message)
588          if (msg.params.detail === "message detail") {
589              // do something
590              // console.log("message info:" + msg.params.detail)
591          }
592      }
593      // ...
594  };
595  ```
596
597## 相关实例
598
599针对Stage模型卡片提供方的开发,有以下相关实例可供参考:
600
601- [FormExtAbility:Stage模型卡片(ArkTS)(API9)](https://gitee.com/openharmony/applications_app_samples/tree/OpenHarmony-3.2-Release/ability/FormExtAbility)
602
603- [GalleryForm:图库卡片(ArkTS)(API9)](https://gitee.com/openharmony/applications_app_samples/tree/OpenHarmony-3.2-Release/ability/GalleryForm)
604