HarmonyOS 鸿蒙Next小部件(Widget)数据同步
HarmonyOS 鸿蒙Next小部件(Widget)数据同步 如何在 HarmonyOS 应用中实现桌面卡片(Form)?如何使用 @kit.FormKit 实现卡片能力?如何将应用数据同步到卡片?如何实现卡片的实时更新?卡片如何与主应用进行数据交互?(问题来源项目案例整理:https://github.com/heqiyuan35-creator/HydroQuiz.git)
3 回复
HarmonyOS 的 FormKit 提供了完整的卡片能力,通过 FormExtensionAbility 和 formProvider 实现卡片与主应用的数据交互。
卡片扩展能力实现(基于 @kit.FormKit):
import { formBindingData, FormExtensionAbility, formInfo, formProvider } from '[@kit](/user/kit).FormKit';
import { Want } from '[@kit](/user/kit).AbilityKit';
import { BusinessError } from '[@kit](/user/kit).BasicServicesKit';
import { preferences } from '[@kit](/user/kit).ArkData';
import { hilog } from '[@kit](/user/kit).PerformanceAnalysisKit';
export default class EntryFormAbility extends FormExtensionAbility {
// 卡片添加时触发(HarmonyOS 生命周期)
onAddForm(want: Want): formBindingData.FormBindingData {
const formId = want.parameters?.[formInfo.FormParam.IDENTITY_KEY] as string;
const formName = want.parameters?.[formInfo.FormParam.NAME_KEY] as string;
// 保存 formId 到 Preferences(用于后续更新)
this.saveFormId(formId);
// 根据卡片名称返回不同数据
if (formName === 'StudyProgress') {
return this.getStudyProgressData();
} else {
return this.getStudyReminderData();
}
}
// 卡片更新时触发
onUpdateForm(formId: string): void {
this.updateFormData(formId);
}
// 卡片事件触发(用户交互)
onFormEvent(formId: string, message: string): void {
try {
const msgObj = JSON.parse(message) as Record<string, string>;
const action = msgObj['action'];
if (action === 'refresh') {
// 刷新卡片数据
this.updateFormData(formId);
}
} catch (error) {
hilog.error(0xFF00, 'EntryFormAbility', `Parse message error`);
}
}
// 卡片移除时触发
onRemoveForm(formId: string): void {
this.removeFormId(formId);
}
// 保存 formId(使用 HarmonyOS Preferences API)
private saveFormId(formId: string): void {
try {
const pref = preferences.getPreferencesSync(this.context, {
name: 'hydro_quiz_prefs'
});
const formIdsStr = pref.getSync('formIds', '') as string;
const formIds = formIdsStr ? formIdsStr.split(',') : [];
if (!formIds.includes(formId)) {
formIds.push(formId);
pref.putSync('formIds', formIds.join(','));
pref.flush();
}
} catch (error) {
hilog.error(0xFF00, 'EntryFormAbility', `Save formId error`);
}
}
// 获取卡片数据(使用 formBindingData)
private getStudyProgressData(): formBindingData.FormBindingData {
const rawData = this.loadStudyData();
const progressData = {
todayCount: rawData.todayCount,
targetCount: rawData.targetCount,
correctCount: rawData.correctCount,
wrongCount: rawData.wrongCount,
accuracy: rawData.todayCount > 0
? Math.round((rawData.correctCount / rawData.todayCount) * 100)
: 0,
progressPercent: rawData.targetCount > 0
? Math.min(100, Math.round((rawData.todayCount / rawData.targetCount) * 100))
: 0
};
// 使用 HarmonyOS API 创建绑定数据
return formBindingData.createFormBindingData(progressData);
}
}
主应用数据同步服务(使用 @kit.FormKit):
import { formBindingData, formProvider } from '[@kit](/user/kit).FormKit';
import { preferences } from '[@kit](/user/kit).ArkData';
import { common } from '[@kit](/user/kit).AbilityKit';
import { BusinessError } from '[@kit](/user/kit).BasicServicesKit';
class WidgetDataService {
private context: common.UIAbilityContext | null = null;
// 同步数据到 Preferences 并更新卡片
async syncData(data: WidgetData): Promise<void> {
if (!this.context) return;
try {
// 使用 HarmonyOS Preferences API
const pref = preferences.getPreferencesSync(this.context, {
name: 'hydro_quiz_prefs'
});
pref.putSync('todayAnswerCount', data.todayCount);
pref.putSync('dailyTarget', data.targetCount);
pref.putSync('todayCorrectCount', data.correctCount);
pref.putSync('todayWrongCount', data.wrongCount);
pref.putSync('isCheckedInToday', data.isCheckedIn);
pref.putSync('streakDays', data.streakDays);
await pref.flush();
// 更新所有卡片
await this.updateAllWidgets(data);
} catch (error) {
Logger.error('Failed to sync data', error as Error);
}
}
// 更新所有卡片(使用 HarmonyOS formProvider API)
private async updateAllWidgets(data: WidgetData): Promise<void> {
if (!this.context) return;
try {
const pref = preferences.getPreferencesSync(this.context, {
name: 'hydro_quiz_prefs'
});
const formIdsStr = pref.getSync('formIds', '') as string;
const formIds = formIdsStr.split(',').filter(id => id.length > 0);
// 构建更新数据
const updateData = {
todayCount: data.todayCount,
targetCount: data.targetCount,
correctCount: data.correctCount,
wrongCount: data.wrongCount,
accuracy: data.todayCount > 0
? Math.round((data.correctCount / data.todayCount) * 100)
: 0,
progressPercent: data.targetCount > 0
? Math.min(100, Math.round((data.todayCount / data.targetCount) * 100))
: 0
};
// 使用 HarmonyOS formBindingData API
const formData = formBindingData.createFormBindingData(updateData);
// 使用 HarmonyOS formProvider API 更新卡片
for (const formId of formIds) {
formProvider.updateForm(formId, formData)
.then(() => {
Logger.info(`Updated form: ${formId}`);
})
.catch((err: BusinessError) => {
Logger.error(`Failed to update form ${formId}: ${err.message}`);
});
}
} catch (error) {
Logger.error('Failed to update widgets', error as Error);
}
}
}
卡片页面实现(ArkUI 组件):
@Entry
@Component
struct StudyProgressCard {
@State todayCount: number = 0;
@State targetCount: number = 20;
@State progressPercent: number = 0;
aboutToAppear(): void {
// 从 Preferences 读取数据(使用 HarmonyOS API)
const pref = preferences.getPreferencesSync(getContext(this), {
name: 'hydro_quiz_prefs'
});
this.todayCount = pref.getSync('todayAnswerCount', 0) as number;
this.targetCount = pref.getSync('dailyTarget', 20) as number;
this.progressPercent = this.targetCount > 0
? Math.min(100, Math.round((this.todayCount / this.targetCount) * 100))
: 0;
}
build() {
Column() {
Text('今日学习')
.fontSize(14)
.fontColor('#333333')
Text(`${this.todayCount}/${this.targetCount}`)
.fontSize(24)
.fontWeight(FontWeight.Bold)
.margin({ top: 8 })
// HarmonyOS Progress 组件
Progress({ value: this.progressPercent, total: 100 })
.width('100%')
.height(8)
.margin({ top: 12 })
}
.padding(16)
.width('100%')
.height('100%')
}
}
更多关于HarmonyOS 鸿蒙Next小部件(Widget)数据同步的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
在HarmonyOS Next中,桌面卡片(Form)通过@kit.FormKit提供能力。以下是关键实现步骤:
1. 创建卡片
- 在
entry/src/main/ets/entryformability/目录下创建FormAbility。 - 使用
FormExtensionAbility生命周期方法管理卡片(如onAddForm创建,onRemoveForm销毁)。 - 通过
formBindingData.createFormBindingData()绑定初始数据。
2. 数据同步与更新
- 主动更新:主应用调用
formProvider.updateForm()推送数据到卡片。 - 定时更新:配置
updateDuration实现周期更新。 - 事件触发更新:通过
postCardAction()发送自定义事件到FormAbility触发更新。
3. 卡片与主应用交互
- 卡片通过
postCardAction()触发主应用指定的want(如打开应用页面)。 - 主应用通过
formProvider接口管理卡片数据。
4. 实时更新关键代码示例
// 主应用更新卡片数据
import formProvider from '@ohos.app.form.formProvider';
let formId = '123456'; // 实际formId
let data = {
temperature: '26℃',
city: '北京'
};
let formData = formBindingData.createFormBindingData(data);
formProvider.updateForm(formId, formData).catch(err => {
console.error(`Failed to update form. Code: ${err.code}, message: ${err.message}`);
});
// 卡片端接收事件更新
import FormExtensionAbility from '@ohos.app.form.FormExtensionAbility';
export default class FormAbility extends FormExtensionAbility {
onFormEvent(formId, message) {
// 根据message事件类型,获取新数据并调用updateForm
}
}
5. 项目适配建议 参考你提供的HydroQuiz项目,需要:
- 在
module.json5中声明extensionAbilities为FormExtensionAbility。 - 将业务数据(如答题结果)通过
formBindingData封装后同步。 - 利用卡片
onFormEvent()处理用户交互(如点击刷新),回调主应用获取最新数据。
通过以上方式,可实现卡片数据动态同步、低功耗定时更新及双向交互能力。注意卡片生命周期独立于主应用,需通过FormExtensionAbility单独管理资源。

