Files
FamilyBook_harmonyos/entry/src/main/ets/entryformability/FbFormAbility.ets
T

93 lines
4.5 KiB
Plaintext
Raw Normal View History

/**
* 家书 FamilyBook · 服务卡片提供方(鸿蒙端 FormExtensionAbility)
*
* 用户 2026-10-20:「做几个和 syncCalendar 差不多的卡片。」
* 参照 `SyncCalendar` 的 `EntryFormAbility`:
* · `onAddForm` —— 添加到桌面时先塞一份"空壳",再异步推真实数据;
* · `onUpdateForm` —— 系统定时刷新(`form_config.json` 里 `updateDuration: 1` ⇒ 30 分钟);
* · `onFormEvent` —— 卡片上的「刷新」按钮(`action: 'message'`);
* · `onRemoveForm` —— 移出桌面。
*
* 🔴 三个必须记住的约束:
* ① **生命周期回调返回后进程只活约 10 秒**(官方文档),所以回调里**不能做长任务**。
* 这里的做法与 SyncCalendar 一致:立刻返回/用本地缓存,真实的网络请求
* 放在 `.then()` 里异步推 —— 就算被回收,也只是"这次没刷成",
* 下一次系统刷新(30 分钟)还会重试。**卡片数据不是关键数据,允许慢一拍。**
* ② `onAddForm` **必须同步返回**一个 `FormBindingData`(不能是 Promise),
* 否则桌面直接显示"卡片加载失败"。
* ③ 数据构建失败**绝不能抛**:抛出去的表现是桌面上一张白卡,
* 用户完全不知道发生了什么。⇒ 失败也返回"带一句人话"的壳(见 `FbCardData.hint`)。
*/
import { FormExtensionAbility, formBindingData, formProvider } from '@kit.FormKit';
import { Want } from '@kit.AbilityKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { FbCardData, fbCardBuild } from '../data/FbCardData';
const DOMAIN: number = 0x0000;
const TAG: string = 'FbForm';
export default class FbFormAbility extends FormExtensionAbility {
/**
* 重新算一遍并推给指定卡片。
*
* ⚠️ 三种尺寸(2×2 / 2×4 / 4×4)共用这一份数据:多算一次就多打一次接口,
* 没有必要 —— 它们只是**排版不同**,数字必须是同一个。
*/
private push(formId: string): void {
fbCardBuild(this.context).then((data: FbCardData): void => {
const binding: formBindingData.FormBindingData = formBindingData.createFormBindingData(data);
formProvider.updateForm(formId, binding).then((): void => {
hilog.info(DOMAIN, TAG, '卡片 %{public}s 已更新(%{public}s)', formId, data.state);
}).catch((err: BusinessError): void => {
// 卡片可能已经被用户删了 —— 打一条日志就够,不要重试
hilog.warn(DOMAIN, TAG, '卡片 %{public}s 更新失败:%{public}s', formId, err.message);
});
}).catch((err: BusinessError): void => {
hilog.error(DOMAIN, TAG, '卡片数据构建失败:%{public}s', err.message);
});
}
/** 从 Want 里取卡片 id(`ohos.extra.param.key.form_identity`) */
private formIdOf(want: Want): string {
if (want.parameters === undefined) {
return '';
}
const raw: Object | undefined = want.parameters['ohos.extra.param.key.form_identity'];
return typeof raw === 'string' ? raw : '';
}
onAddForm(want: Want): formBindingData.FormBindingData {
const formId: string = this.formIdOf(want);
hilog.info(DOMAIN, TAG, '添加卡片:%{public}s', formId);
if (formId !== '') {
// 异步补真实数据(不 await:见文件头约束 ①)
this.push(formId);
}
// 先给一份"正在取"的壳 —— 卡片上会显示这天/这周的空状态,而不是白屏
const shell: FbCardData = new FbCardData();
shell.state = 'loading';
shell.hint = '正在取数据…';
return formBindingData.createFormBindingData(shell);
}
onUpdateForm(formId: string): void {
hilog.info(DOMAIN, TAG, '系统定时刷新:%{public}s', formId);
this.push(formId);
}
onFormEvent(formId: string, message: string): void {
/* 卡片上的按钮都走 `action: 'message'`,`message` 是 JSON 字符串。
⚠️ 不解析 JSON:不同版本系统给的形态可能是 `{params:{...}}` 或直接 `{...}`,
子串匹配更稳(与 SyncCalendar 同一个取舍)。 */
hilog.info(DOMAIN, TAG, '卡片事件:%{public}s %{public}s', formId, message);
this.push(formId);
}
onRemoveForm(formId: string): void {
// 本卡片不落任何"每张卡"的状态(没有翻页偏移之类),所以只需记一条日志
hilog.info(DOMAIN, TAG, '移除卡片:%{public}s', formId);
}
}