类文件存在,不代表卡片已经接通
这次检查的工程里有一个 FormExtensionAbility 子类,也有 ArkTS 卡片 UI。生命周期方法大多还是空模板:创建时绑定空字符串,更新、事件和删除回调没有业务处理。更关键的是,模块清单里没有注册 type: "form" 的扩展,资源目录也没有 form_config.json。
所以现状不是“卡片已完整可用”,而是卡片 UI 与 Provider 的代码雏形已经存在,系统发现和调度所需的声明链路还缺一段。ArkTS 卡片至少要把模块注册、卡片元数据、数据绑定、更新策略和交互目标连起来。
第一步:在模块清单里注册 Provider
在 entry/src/main/module.json5 的 module 对象中补充扩展声明。名称与源码路径按自己的目录结构调整:
{
"module": {
"extensionAbilities": [
{
"name": "OverviewFormAbility",
"srcEntry": "./ets/formability/OverviewFormAbility.ets",
"type": "form",
"label": "$string:overview_form_label",
"metadata": [
{
"name": "ohos.extension.form",
"resource": "$profile:form_config"
}
]
}
]
}
}
metadata 将扩展与卡片资源关联起来。对应的资源文件可放在 entry/src/main/resources/base/profile/form_config.json:
{
"forms": [
{
"name": "OverviewCard",
"description": "信息摘要",
"src": "./ets/widget/pages/OverviewCard.ets",
"uiSyntax": "arkts",
"isDefault": true,
"colorMode": "auto",
"defaultDimension": "2*2",
"supportDimensions": ["2*2"],
"updateEnabled": false
}
]
}
上面的卡片关闭定时刷新,适合展示由应用主动更新的轻量摘要。若要使用系统定时刷新,应结合目标 API 版本核对 updateEnabled、updateDuration 和刷新频率限制;不要为了“看起来实时”而设置过密的刷新周期。
第二步:让生命周期返回稳定的数据结构
卡片 UI 声明自己需要哪些字段,Provider 就返回相同结构。这样首次创建与后续更新使用同一份数据契约,避免第一次有内容、刷新后字段消失。
import {
formBindingData,
FormExtensionAbility,
formInfo,
formProvider
} from '@kit.FormKit';
import { Want } from '@kit.AbilityKit';
import { BusinessError } from '@kit.BasicServicesKit';
interface OverviewData {
title: string;
summary: string;
}
function createOverviewData(): OverviewData {
return {
title: '服务概览',
summary: '当前状态:已同步'
};
}
export default class OverviewFormAbility extends FormExtensionAbility {
onAddForm(want: Want): formBindingData.FormBindingData {
const data: OverviewData = createOverviewData();
return formBindingData.createFormBindingData(data);
}
onUpdateForm(formId: string): void {
this.updateSnapshot(formId);
}
onFormEvent(formId: string, message: string): void {
try {
const payload: Record<string, Object> = JSON.parse(message) as Record<string, Object>;
if (payload['message'] === 'refresh') {
this.updateSnapshot(formId);
}
} catch (error) {
console.error(`Invalid form event: ${JSON.stringify(error)}`);
}
}
onCastToNormalForm(formId: string): void {
// 临时卡片转为常驻卡片时,按需调整实例状态。
}
private updateSnapshot(formId: string): void {
const data: OverviewData = createOverviewData();
const binding = formBindingData.createFormBindingData(data);
formProvider.updateForm(formId, binding).catch((error: BusinessError) => {
console.error(`updateForm failed: ${JSON.stringify(error)}`);
});
}
onRemoveForm(formId: string): void {
// 如有按 formId 保存的实例状态,在这里清理。
}
onAcquireFormState(want: Want): formInfo.FormState {
return formInfo.FormState.READY;
}
}
UI 侧用相同的字段名接收绑定数据,例如:
@Component
struct OverviewCard {
@LocalStorageProp('title') title: string = '加载中';
@LocalStorageProp('summary') summary: string = '';
build() {
Column() {
Text(this.title).fontSize(16).fontWeight(FontWeight.Medium)
Text(this.summary).fontSize(13).maxLines(2)
Button('刷新').onClick(() => {
postCardAction(this, {
action: 'message',
params: { message: 'refresh' }
});
})
}
.width('100%')
.height('100%')
.padding(16)
}
}
这份代码是数据流示例:onAddForm 返回首次数据,ArkUI 用 LocalStorage 属性渲染;系统更新回调和卡片消息事件都进入同一个轻量刷新函数。onRemoveForm 则负责按 formId 清理实例状态。实际项目还要根据支持的卡片尺寸检查文本折行、图片快照和深浅色模式。
生命周期里不要跑长任务
FormExtensionAbility 不是常驻后台服务。官方生命周期说明指出,回调完成后进程最多只会短暂保留,超过约 10 秒没有新的生命周期调用就会退出。因此卡片 Provider 适合快速读取已有摘要、更新绑定或处理轻量消息;长网络请求、复杂计算和持续任务应交给正常应用流程处理,完成后再更新卡片。
按 formId 保存卡片状态时,要处理创建和删除的对称关系:onAddForm 读取创建参数并初始化状态,onRemoveForm 删除对应状态;多个卡片实例不能共享一个无区分的全局值。刷新失败也应保留上次可用内容,记录有限的错误信息,避免每次系统回调都触发昂贵的重试。
接回现有工程时的检查顺序
- 清单里的
extensionAbilities名称、源码路径和type能对应起来。 ohos.extension.form的资源路径指向实际存在的form_config.json。src指向真实 ArkTS 卡片页面,且数据键与 Provider 返回对象一致。onUpdateForm成功调用formProvider.updateForm,错误路径也可观察。- 每种尺寸和主题都能显示;移除实例后不会留下陈旧状态。
- 最后按目标元服务产物验证卡片的系统入口与分发限制。
工程快照中的空回调和未注册资源,使这份检查清单尤其重要:先让系统识别卡片,再谈刷新频率与业务数据。
参考资料
上一篇:HarmonyOS 元服务配置核查:atomicService 与 installationFree 的边界 · 下一篇:HarmonyOS 元服务深链路由:处理 Want 冷热启动与页面栈时序。
