鸿蒙实战:元服务与卡片开发全攻略

一、我们要做什么
1.1 项目背景
在移动互联网时代,用户对服务的获取效率要求越来越高。传统应用需要下载、安装、注册等繁琐步骤,用户体验门槛较高。HarmonyOS 创新性地提出"元服务"概念,即原子化服务,它具备以下核心特征:
- 免安装:用户无需安装完整应用,点击即用
- 轻量化:功能聚焦,包体体积小
- 服务直达:通过卡片、搜索、分享等多入口触达用户
- 跨设备流转:支持多设备无缝协同
卡片(Form)是元服务最重要的展示形态之一,它允许应用将关键信息直接呈现在桌面,用户无需打开应用即可查看动态内容,如天气、待办、运动数据等。
1.2 需求分析
本案例将开发一个"每日打卡"元服务卡片,实现以下核心功能:
| 功能模块 | 需求描述 | 优先级 |
|---|---|---|
| 卡片展示 | 显示打卡天数、今日状态、快捷操作按钮 | P0 |
| 数据更新 | 支持定时刷新(每日零点)与手动刷新 | P0 |
| 交互通信 | 卡片点击触发主体应用打卡操作 | P0 |
| 多尺寸适配 | 支持 2×2、2×4 两种尺寸卡片 | P1 |
| 主题切换 | 支持亮色/暗色主题自动适配 | P2 |
1.3 预期效果
用户在桌面长按添加卡片后,将看到以下效果:
┌─────────────────────────┐
│ 📅 每日打卡 │
│ ───────────────────── │
│ 已连续打卡: 28 天 │
│ 今日状态: ✅ 已完成 │
│ ───────────────────── │
│ [立即打卡] [查看详情] │
└─────────────────────────┘
卡片每日零点自动刷新数据,点击"立即打卡"按钮可触发打卡操作并更新显示。
1.4 技术挑战
开发过程中需要解决以下技术挑战:
- 卡片生命周期管理:FormExtensionAbility 的创建、更新、销毁时机
- 数据同步机制:卡片与主体应用的数据一致性保障
- 跨进程通信:卡片运行在独立进程,如何与主应用通信
- 性能优化:卡片刷新频率控制,避免资源浪费
- 多尺寸适配:不同尺寸卡片的布局与数据差异化处理
二、数据模型设计
2.1 卡片数据模型
首先定义卡片核心数据结构,使用 TypeScript interface 强类型约束:
// CardData.ets
export interface CardData {
// 打卡统计数据
totalDays: number; // 累计打卡天数
continuousDays: number; // 连续打卡天数
todayStatus: CheckStatus; // 今日状态
// 时间信息
lastCheckTime: string; // 最后打卡时间
nextRefreshTime: string; // 下次刷新时间
// 显示配置
theme: ThemeMode; // 主题模式
cardSize: CardSize; // 卡片尺寸
}
export enum CheckStatus {
NOT_CHECKED = 0, // 未打卡
CHECKED = 1, // 已打卡
EXPIRED = 2 // 已过期
}
export enum ThemeMode {
LIGHT = 'light',
DARK = 'dark',
AUTO = 'auto'
}
export enum CardSize {
SIZE_2X2 = '2x2',
SIZE_2X4 = '2x4'
}
2.2 表单配置模型
FormLink 配置用于定义卡片跳转行为:
// FormConfig.ets
export interface FormConfig {
// 卡片基础配置
formId: string; // 卡片唯一标识
formName: string; // 卡片名称
displayName: string; // 显示名称
description: string; // 描述信息
// 尺寸配置
supportDimensions: CardSize[]; // 支持的尺寸
defaultDimension: CardSize; // 默认尺寸
// 刷新配置
updateEnabled: boolean; // 是否启用更新
updateDuration: number; // 更新间隔(小时)
scheduledUpdateTime: string; // 定时更新时间
}
export interface FormAction {
actionType: FormActionType;
abilityName: string;
params: Record<string, string>;
}
export enum FormActionType {
ROUTER = 'router', // 跳转能力
CALL = 'call', // 调用能力
MESSAGE = 'message' // 消息能力
}
2.3 状态管理模型
卡片状态用于追踪运行时数据:
// CardState.ets
export interface CardState {
formId: string;
createTime: number;
lastUpdateTime: number;
isDirty: boolean; // 数据是否需要更新
retryCount: number; // 重试次数
}
export class CardStateManager {
private states: Map<string, CardState> = new Map();
getState(formId: string): CardState | undefined {
return this.states.get(formId);
}
updateState(formId: string, updates: Partial<CardState>): void {
const current = this.states.get(formId);
if (current) {
this.states.set(formId, { ...current, ...updates });
}
}
addState(formId: string): void {
this.states.set(formId, {
formId,
createTime: Date.now(),
lastUpdateTime: Date.now(),
isDirty: false,
retryCount: 0
});
}
removeState(formId: string): void {
this.states.delete(formId);
}
}
三、核心设计决策
3.1 卡片类型选型
| 对比维度 | 静态卡片 | 动态卡片 (ArkTS) |
|---|---|---|
| UI 能力 | 基础布局、图片、文字 | 完整 ArkUI 组件 |
| 交互能力 | 仅支持点击跳转 | 支持动画、手势 |
| 刷新方式 | 全量更新 | 局部刷新、定时器 |
| 性能开销 | 低 | 中 |
| 开发复杂度 | 低 | 中 |
| 适用场景 | 信息展示类 | 交互复杂类 |
选型理由:本项目选择 ArkTS 动态卡片,原因如下:
- 需要支持按钮点击交互
- 需要实现状态切换动画效果
- 需要局部刷新以提升用户体验
- 后续扩展需要更多自定义能力
3.2 卡片与主应用通信方案
| 方案 | 原理 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|---|
| FormLink Router | 通过 uri 启动 Ability | 简单可靠 | 无法传复杂数据 | 跳转页面 |
| FormLink Call | 调用 Ability 方法 | 双向通信 | 需要权限配置 | 执行操作 |
| DataShare | 共享数据存储 | 数据持久化 | 需要额外实现 | 数据同步 |
| CommonEvent | 发布订阅事件 | 松耦合 | 异步延迟低 | 事件通知 |
选型理由:本项目采用 FormLink Call + CommonEvent 组合方案:
- FormLink Call 用于卡片触发主应用打卡操作
- CommonEvent 用于主应用通知卡片数据更新
3.3 数据更新策略
| 策略 | 实现方式 | 适用场景 |
|---|---|---|
| 定时更新 | form_update_duration 配置 | 周期性数据刷新 |
| 请求更新 | updateForm() 主动调用 | 事件驱动更新 |
| 条件更新 | 网络恢复、应用切换 | 智能刷新 |
选型理由:采用混合更新策略:
- 配置每日零点定时更新
- 用户打卡后主动触发更新
- 网络恢复后检查并更新
四、完整代码实现
4.1 FormExtensionAbility 实现
FormExtensionAbility 是卡片的核心能力组件,负责处理卡片生命周期回调:
// entry/src/main/ets/formability/FormAbility.ets
import FormExtensionAbility from '@ohos.app.ability.FormExtensionAbility';
import formProvider from '@ohos.app.form.formProvider';
import formBindingData from '@ohos.app.form.formBindingData';
import { CardData, CheckStatus } from '../model/CardData';
export default class FormAbility extends FormExtensionAbility {
// 卡片创建时调用
onAddForm(want: Want): formBindingData.FormBindingData {
console.info('[FormAbility] onAddForm called');
const formId = want.parameters?.['ohos.extra.param.key.form_identity'];
const formName = want.parameters?.['ohos.extra.param.key.form_name'];
const dimension = want.parameters?.['ohos.extra.param.key.form_dimension'];
// 初始化卡片数据
const cardData = this.initCardData(formId, dimension);
// 创建绑定数据
return formBindingData.createFormBindingData(cardData);
}
// 卡片更新时调用
onUpdateForm(formId: string): void {
console.info(`[FormAbility] onUpdateForm: ${formId}`);
// 获取最新数据
const cardData = this.fetchLatestData(formId);
// 构建更新数据
const bindingData = formBindingData.createFormBindingData(cardData);
// 通知卡片更新
formProvider.updateForm(formId, bindingData).then(() => {
console.info('[FormAbility] Update success');
}).catch((err: Error) => {
console.error(`[FormAbility] Update failed: ${err.message}`);
});
}
// 卡片移除时调用
onRemoveForm(formId: string): void {
console.info(`[FormAbility] onRemoveForm: ${formId}`);
// 清理相关数据
this.cleanupFormData(formId);
}
// 卡片事件处理
onFormEvent(formId: string, message: string): void {
console.info(`[FormAbility] onFormEvent: ${formId}, ${message}`);
const event = JSON.parse(message);
if (event.action === 'check_in') {
this.handleCheckIn(formId);
}
}
private initCardData(formId: string, dimension: number): CardData {
return {
totalDays: 0,
continuousDays: 0,
todayStatus: CheckStatus.NOT_CHECKED,
lastCheckTime: '',
nextRefreshTime: '00:00',
theme: 'auto',
cardSize: dimension === 4 ? '2x4' : '2x2'
};
}
private fetchLatestData(formId: string): CardData {
// 从持久化存储获取数据
// 实际项目中应从数据库或网络获取
return this.initCardData(formId, 2);
}
private cleanupFormData(formId: string): void {
// 清理本地缓存的卡片数据
}
private handleCheckIn(formId: string): void {
// 处理打卡逻辑
console.info(`[FormAbility] Handle check-in for ${formId}`);
}
}
4.2 配置文件声明
在 module.json5 中声明卡片能力:
{
"module": {
"abilities": [
{
"name": "FormAbility",
"srcEntry": "./ets/formability/FormAbility.ets",
"type": "form",
"label": "$string:form_ability_label",
"description": "$string:form_ability_desc",
"metadata": [
{
"name": "ohos.extension.form",
"resource": "$profile:form_config"
}
]
}
]
}
}
在 form_config.json 中配置卡片参数:
{
"forms": [
{
"name": "CheckInCard",
"displayName": "$string:card_name",
"description": "$string:card_desc",
"src": "./ets/cards/CheckInCard.ets",
"uiSyntax": "arkts",
"window": {
"designWidth": 720,
"autoDesignWidth": true
},
"colorMode": "auto",
"isDefault": true,
"updateEnabled": true,
"scheduledUpdateTime": "00:00",
"updateDuration": 24,
"defaultDimension": "2*2",
"supportDimensions": ["2*2", "2*4"]
}
]
}
4.3 ArkTS 卡片 UI 实现
使用 ArkUI 声明式语法构建卡片界面:
// entry/src/main/ets/cards/CheckInCard.ets
@Entry
@Component
struct CheckInCard {
// 卡片数据绑定
@LocalStorageProp('totalDays') totalDays: number = 0;
@LocalStorageProp('continuousDays') continuousDays: number = 0;
@LocalStorageProp('todayStatus') todayStatus: number = 0;
@LocalStorageProp('lastCheckTime') lastCheckTime: string = '';
build() {
Column() {
// 标题区域
Row() {
Text('📅 每日打卡')
.fontSize(18)
.fontWeight(FontWeight.Bold)
.fontColor('#1a1a1a')
Blank()
// 刷新按钮
Image($r('app.media.ic_refresh'))
.width(20)
.height(20)
.onClick(() => this.onRefresh())
}
.width('100%')
.padding({ left: 16, right: 16, top: 12 })
Divider().color('#e5e5e5')
// 数据展示区域
Column() {
Row() {
Text('累计打卡')
.fontSize(14)
.fontColor('#666666')
Text(`${this.totalDays} 天`)
.fontSize(20)
.fontWeight(FontWeight.Bold)
.fontColor('#1890ff')
}
.width('100%')
.justifyContent(FlexAlign.SpaceBetween)
.margin({ top: 12 })
Row() {
Text('连续打卡')
.fontSize(14)
.fontColor('#666666')
Text(`${this.continuousDays} 天`)
.fontSize(20)
.fontWeight(FontWeight.Bold)
.fontColor('#52c41a')
}
.width('100%')
.justifyContent(FlexAlign.SpaceBetween)
.margin({ top: 8 })
// 今日状态
Row() {
Text('今日状态:')
.fontSize(14)
.fontColor('#666666')
Text(this.getStatusText())
.fontSize(14)
.fontWeight(FontWeight.Medium)
.fontColor(this.getStatusColor())
}
.margin({ top: 8 })
}
.padding({ left: 16, right: 16 })
Blank()
// 操作按钮区域
Row() {
Button('立即打卡')
.fontSize(14)
.fontColor('#ffffff')
.backgroundColor('#1890ff')
.borderRadius(16)
.height(32)
.enabled(this.todayStatus === 0)
.onClick(() => this.onCheckIn())
Button('查看详情')
.fontSize(14)
.fontColor('#1890ff')
.backgroundColor('#e6f7ff')
.borderRadius(16)
.height(32)
.margin({ left: 12 })
.onClick(() => this.onViewDetail())
}
.width('100%')
.justifyContent(FlexAlign.Center)
.padding({ bottom: 16 })
}
.width('100%')
.height('100%')
.backgroundColor('#ffffff')
.borderRadius(16)
}
private getStatusText(): string {
switch (this.todayStatus) {
case 1: return '✅ 已完成';
case 2: return '⏰ 已过期';
default: return '⭕ 未打卡';
}
}
private getStatusColor(): ResourceColor {
switch (this.todayStatus) {
case 1: return '#52c41a';
case 2: return '#ff4d4f';
default: return '#faad14';
}
}
private onRefresh(): void {
// 触发刷新
postCardAction(this, {
action: 'message',
params: { cmd: 'refresh' }
});
}
private onCheckIn(): void {
// 触发打卡
postCardAction(this, {
action: 'call',
abilityName: 'EntryAbility',
params: { method: 'checkIn' }
});
}
private onViewDetail(): void {
// 跳转详情页
postCardAction(this, {
action: 'router',
abilityName: 'EntryAbility',
params: { page: 'CheckInDetail' }
});
}
}
4.4 卡片数据更新机制
实现定时刷新与主动更新:
// entry/src/main/ets/service/CardUpdateService.ets
import formProvider from '@ohos.app.form.formProvider';
import formBindingData from '@ohos.app.form.formBindingData';
import backgroundTaskManager from '@ohos.resourceschedule.backgroundTaskManager';
export class CardUpdateService {
private static instance: CardUpdateService;
private formIds: Set<string> = new Set();
static getInstance(): CardUpdateService {
if (!CardUpdateService.instance) {
CardUpdateService.instance = new CardUpdateService();
}
return CardUpdateService.instance;
}
// 注册卡片
registerForm(formId: string): void {
this.formIds.add(formId);
console.info(`[CardUpdateService] Register form: ${formId}`);
}
// 注销卡片
unregisterForm(formId: string): void {
this.formIds.delete(formId);
console.info(`[CardUpdateService] Unregister form: ${formId}`);
}
// 更新所有卡片
async updateAllCards(): Promise<void> {
const promises: Promise<void>[] = [];
this.formIds.forEach(formId => {
promises.push(this.updateCard(formId));
});
await Promise.allSettled(promises);
}
// 更新单个卡片
async updateCard(formId: string): Promise<void> {
try {
const data = await this.fetchCardData(formId);
const bindingData = formBindingData.createFormBindingData(data);
await formProvider.updateForm(formId, bindingData);
console.info(`[CardUpdateService] Card updated: ${formId}`);
} catch (error) {
console.error(`[CardUpdateService] Update failed: ${error}`);
}
}
// 获取卡片数据
private async fetchCardData(formId: string): Promise<CardData> {
// 从数据层获取最新数据
return {
totalDays: 30,
continuousDays: 7,
todayStatus: 1,
lastCheckTime: new Date().toISOString(),
nextRefreshTime: '00:00',
theme: 'auto',
cardSize: '2x2'
};
}
// 设置定时刷新
setupScheduledRefresh(): void {
// 计算到下一个零点的时间
const now = new Date();
const nextMidnight = new Date(
now.getFullYear(),
now.getMonth(),
now.getDate() + 1,
0, 0, 0
);
const delay = nextMidnight.getTime() - now.getTime();
// 申请后台任务
backgroundTaskManager.requestSuspendDelay('card-refresh', () => {
console.info('[CardUpdateService] Background task expired');
});
// 延迟执行刷新
setTimeout(() => {
this.updateAllCards();
this.setupScheduledRefresh();
}, delay);
}
}
4.5 卡片与主应用通信
实现双向通信机制:
// entry/src/main/ets/entryability/EntryAbility.ets
import UIAbility from '@ohos.app.ability.UIAbility';
import CommonEvent from '@ohos.commonEvent';
import { CardUpdateService } from '../service/CardUpdateService';
export default class EntryAbility extends UIAbility {
private cardService: CardUpdateService = CardUpdateService.getInstance();
private eventSubscriber: CommonEvent.CommonEventSubscriber | null = null;
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
// 处理卡片触发的启动
if (want.parameters?.method === 'checkIn') {
this.handleCheckIn(want);
}
if (want.parameters?.page) {
// 跳转到指定页面
this.startPage(want.parameters.page as string);
}
// 订阅卡片更新事件
this.subscribeCardEvents();
}
private handleCheckIn(want: Want): void {
const formId = want.parameters?.formId as string;
// 执行打卡逻辑
this.performCheckIn().then(success => {
if (success) {
// 通知卡片更新
this.cardService.updateCard(formId);
// 发送广播通知
this.publishCheckInEvent(formId);
}
});
}
private async performCheckIn(): Promise<boolean> {
// 实际打卡逻辑
console.info('[EntryAbility] Performing check-in');
return true;
}
private publishCheckInEvent(formId: string): void {
const options: CommonEvent.CommonEventPublishData = {
parameters: {
formId: formId,
action: 'check_in_complete'
}
};
CommonEvent.publish('com.example.checkin.event', options, (err) => {
if (err) {
console.error(`[EntryAbility] Publish event failed: ${err.code}`);
}
});
}
private subscribeCardEvents(): void {
const subscribeInfo: CommonEvent.CommonEventSubscribeInfo = {
events: ['com.example.card.refresh']
};
CommonEvent.createSubscriber(subscribeInfo, (err, subscriber) => {
if (!err && subscriber) {
this.eventSubscriber = subscriber;
CommonEvent.subscribe(subscriber, (err, data) => {
if (!err && data) {
const formId = data.parameters?.formId as string;
if (formId) {
this.cardService.updateCard(formId);
}
}
});
}
});
}
private startPage(page: string): void {
// 启动指定页面
console.info(`[EntryAbility] Navigate to: ${page}`);
}
}
五、深度技术原理
5.1 卡片架构与渲染隔离
HarmonyOS 卡片采用严格的进程隔离架构,确保安全性与稳定性:
┌─────────────────────────────────────────────┐
│ 系统服务层 │
│ ┌─────────────┐ ┌─────────────┐ │
│ │ FormManager │ │ FormRenderer │ │
│ └─────────────┘ └─────────────┘ │
└─────────────────────────────────────────────┘
↓ ↓
┌─────────────────┐ ┌─────────────────┐
│ 主应用进程 │ │ 卡片渲染进程 │
│ ┌───────────┐ │ │ ┌───────────┐ │
│ │UIAbility │ │ │ │ArkUI引擎 │ │
│ │FormExt. │ │ │ │渲染器 │ │
│ └───────────┘ │ │ └───────────┘ │
└─────────────────┘ └─────────────────┘
核心机制:
- 进程隔离:卡片运行在独立沙箱进程,即使崩溃也不影响主应用
- 渲染分离:卡片 UI 由 FormRenderer 独立渲染,资源隔离
- 数据绑定:通过 FormBindingData 实现数据与 UI 解耦
- 安全边界:卡片无法直接访问主应用内存,通过 IPC 通信
5.2 卡片刷新机制
卡片刷新采用多层次策略:
| 刷新类型 | 触发条件 | 频率限制 | 实现方式 |
|---|---|---|---|
| 定时刷新 | scheduledUpdateTime | 最低 1 小时 | 系统调度 |
| 请求刷新 | updateForm() 调用 | 无限制 | 开发者控制 |
| 事件刷新 | CommonEvent 触发 | 无限制 | 事件驱动 |
定时刷新原理:
系统 FormManagerService 维护卡片刷新队列,在设定时间触发 onAddForm 回调。开发者需要在回调中返回最新的 FormBindingData,系统自动更新卡片 UI。
性能优化建议:
- 避免高频刷新(建议最低间隔 1 小时)
- 使用增量更新减少数据传输量
- 在 onRemoveForm 中释放资源
- 合理使用后台任务延长刷新窗口
5.3 跨进程通信详解
卡片与主应用的跨进程通信(IPC)有以下路径:
FormLink Router 路径:
卡片进程 → FormManagerService → AbilityManagerService → 主应用进程
FormLink Call 路径:
卡片进程 → FormManagerService → IPC调用 → 主应用FormExtensionAbility
CommonEvent 路径:
发布者 → CommonEventService → 订阅者(卡片/应用)
通信性能对比:
| 方式 | 延迟 | 数据量 | 方向 |
|---|---|---|---|
| Router | ~100ms | URI 参数 | 单向 |
| Call | ~50ms | 序列化数据 | 双向 |
| CommonEvent | ~30ms | 事件参数 | 广播 |
5.4 元服务分发链路
元服务从开发到用户桌面的完整链路:
开发者上传 → 应用市场审核 → 云端分发 → 用户搜索/分享 → 免安装加载
↓
桌面卡片 → 服务直达
关键技术环节:
- 原子化封装:元服务独立打包,最小化体积
- 签名校验:多层签名验证确保完整性
- 按需加载:先加载核心代码,资源懒加载
- 缓存策略:已使用元服务本地缓存
- 跨设备流转:分布式数据同步
六、常见问题解答
Q1: 卡片不显示或显示空白?
原因分析:
- form_config.json 配置错误
- ArkTS 卡片文件路径不正确
- 卡片组件编译失败
解决方案:
- 检查 module.json5 中 metadata 引用的配置文件
- 确认卡片源文件路径与配置一致
- 查看 DevEco Studio 编译输出日志
- 确保卡片组件使用 @Entry 装饰器
Q2: 卡片刷新不生效?
原因分析:
- updateForm 未正确调用
- FormBindingData 数据格式错误
- 系统限制刷新频率
解决方案:
- 检查 updateForm 回调是否返回有效数据
- 确认数据字段名与卡片组件绑定一致
- 避免短时间频繁调用 updateForm
- 检查后台任务是否被系统回收
Q3: 卡片点击无响应?
原因分析:
- postCardAction 参数错误
- 目标 Ability 未正确配置
- 权限不足
解决方案:
- 确认 action 参数使用正确(router/call/message)
- 检查目标 Ability 是否在 module.json5 声明
- 查看 HiLog 日志确认事件是否触发
- 验证 form_config.json 中的 ability 配置
Q4: 如何实现卡片深色模式适配?
解决方案:
- 在 form_config.json 设置
"colorMode": "auto" - 使用系统资源
$r('sys.color.xxx')自动适配 - 在卡片组件中监听系统主题变化
@StorageLink('systemTheme') systemTheme: string = 'light';
build() {
Column() {
// 使用条件样式
Text('打卡')
.fontColor(this.systemTheme === 'dark' ? '#ffffff' : '#1a1a1a')
}
}
Q5: 卡片数据如何持久化?
解决方案:
使用 Preferences 或数据库存储卡片数据:
import preferences from '@ohos.data.preferences';
// 保存数据
async saveCardData(formId: string, data: CardData): Promise<void> {
const prefs = await preferences.getPreferences(this.context, 'card_data');
await prefs.put(formId, JSON.stringify(data));
await prefs.flush();
}
// 读取数据
async loadCardData(formId: string): Promise<CardData | null> {
const prefs = await preferences.getPreferences(this.context, 'card_data');
const data = await prefs.get(formId, '');
return data ? JSON.parse(data as string) : null;
}
Q6: 卡片支持哪些组件?
ArkTS 卡片支持的核心组件:
- 基础组件:Text、Image、Button、Toggle
- 容器组件:Column、Row、Stack、Flex
- 渲染控制:ForEach、LazyForEach
- 特殊组件:Progress、Divider、Blank
不支持的功能:
- 自定义组件(@Component 装饰的非内置组件)
- WebView
- 视频播放组件
- 部分动画效果
七、运行效果
7.1 卡片生命周期流程

7.2 卡片交互流程
┌──────────────────────────────────────────────────────┐
│ 桌面卡片 │
│ ┌────────────────────────────────────────────────┐ │
│ │ [立即打卡] [查看详情] │ │
│ └────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────┘
│ click │ click
▼ ▼
┌─────────────┐ ┌─────────────┐
│ FormLink │ │ FormLink │
│ Call │ │ Router │
└─────────────┘ └─────────────┘
│ │
▼ ▼
┌─────────────┐ ┌─────────────┐
│ 主应用执行 │ │ 启动页面 │
│ 打卡逻辑 │ │ EntryAbility│
└─────────────┘ └─────────────┘
│
▼
┌─────────────┐
│ 更新卡片 │
│ 数据与UI │
└─────────────┘
7.3 多尺寸卡片展示
2×2 尺寸(简洁版):
2×4 尺寸(详细版):
八、扩展方向
8.1 多设备适配
利用 HarmonyOS 分布式能力,实现卡片跨设备同步:
- 手机端打卡,平板/手表同步显示
- 卡片状态云端备份与恢复
- 跨设备拖拽迁移卡片
8.2 智能推荐
结合 AI 能力增强卡片智能化:
- 基于用户习惯推荐最佳打卡时间
- 智能调整卡片刷新频率
- 异常数据智能预警
8.3 服务联动
将卡片融入 HarmonyOS 服务生态:
- 与其他元服务联动(运动数据同步)
- 桌面小组件搜索直达
- 小艺建议智能推送
8.4 性能优化进阶
深入优化卡片性能:
- 增量更新机制减少数据传输
- 图片资源按需加载与缓存
- 复杂动画降级策略
更多推荐




所有评论(0)