一个看似简单的小组件,踩了十几个坑,从进程隔离到跨 Context 通信,从 Builder 传参 Bug 到精度丢失——这篇文章带你完整走一遍鸿蒙卡片开发的真实体验。
背景
我们的 App 是一个运动健康类应用(类似 Keep),需要开发三个桌面卡片:
- 本周跑步(2×2):显示本周 7 天柱状图 + 总距离
- 本月跑步(2×4):显示日历热力图 + 统计数据
- 本年跑步(4×4):显示 12 个月柱状图 + 统计数据
数据来源于服务端 API,需要实现以下刷新时机:
- 用户登录后刷新数据
- 上传运动数据后刷新
- 退出登录时清空数据
听起来很简单对吧?我也这么想的。直到我打开了鸿蒙的官方文档…
架构设计:谁来做数据请求?
第一版(错误):鸿蒙端自己做 HTTP 请求
最初的想法是在鸿蒙端的 FormExtensionAbility 中直接调用 HTTP API 获取数据。
为什么错了?
我们的 Flutter 代码中已经有完整的 API 定义(Retrofit + Dio),包括 Token 管理、错误处理、数据模型。如果在鸿蒙端再写一遍:
- 代码重复,维护两套 API 层
- Token 管理复杂(鸿蒙端需要从 Flutter 传 Token)
- 数据模型要两边对齐
最终方案:Flutter 拉数据,MethodChannel 传数据
Flutter 调用 API → 拿到数据 → jsonEncode → MethodChannel → 鸿蒙 Plugin 接收 → 存储 → 刷新卡片
鸿蒙端只负责接收数据、存储、刷新 UI,不做任何网络请求。
第一坑:数据写入了但卡片不刷新——进程隔离的真相
这是整个开发过程中最大的坑。
问题现象
Flutter 端 API 返回数据 → MethodChannel 传到鸿蒙 → SportWidgetPlugin 收到 → 写入数据 → 但卡片显示的还是空数据。
排查过程
- 数据写入成功:
saveWidgetData日志显示数据正常 - 读取为空:FormAbility 的
onUpdateForm中读数据时,json length=0 - 怀疑 Preferences 不互通:Plugin 用
ApplicationContext,FormAbility 用FormExtensionContext
查阅官方文档后找到关键信息:
卡片提供方进程:提供卡片的应用进程,包括应用自身 UIAbility 运行的主进程,以及卡片单独的 FormExtensionAbility 进程。两个进程之间内存隔离,但是共享相同的文件沙箱。
真相大白:
- Plugin 运行在主进程
- FormAbility 运行在独立进程
- 两个进程的 Context 不同 → Preferences 存储路径不同 → 数据不互通
- 静态变量也不通(不同进程内存隔离)
- 文件沙箱共享 ← 这是突破口
解决方案:用文件存储桥接两个进程
Plugin(主进程) → 写文件 (ApplicationContext.filesDir/szxd_widget_data_week.json)
↓ 共享文件沙箱
FormAbility(独立进程) → 读文件 (ApplicationContext.filesDir/szxd_widget_data_week.json)
核心代码:
// WidgetDataFileStore.ets - 跨进程共享的文件存储
export class WidgetDataFileStore {
// 关键:用 getApplicationContext().filesDir,主进程和 FormAbility 进程都能访问
private static getFilePath(context: common.Context, type: SportWidgetType): string {
const appContext = context.getApplicationContext();
return appContext.filesDir + '/'


1万+

被折叠的 条评论
为什么被折叠?



