在这里插入图片描述

一、我们要做什么

1.1 项目背景

在移动互联网时代,用户对服务的获取效率要求越来越高。传统应用需要下载、安装、注册等繁琐步骤,用户体验门槛较高。HarmonyOS 创新性地提出"元服务"概念,即原子化服务,它具备以下核心特征:

  • 免安装:用户无需安装完整应用,点击即用
  • 轻量化:功能聚焦,包体体积小
  • 服务直达:通过卡片、搜索、分享等多入口触达用户
  • 跨设备流转:支持多设备无缝协同

卡片(Form)是元服务最重要的展示形态之一,它允许应用将关键信息直接呈现在桌面,用户无需打开应用即可查看动态内容,如天气、待办、运动数据等。

1.2 需求分析

本案例将开发一个"每日打卡"元服务卡片,实现以下核心功能:

功能模块 需求描述 优先级
卡片展示 显示打卡天数、今日状态、快捷操作按钮 P0
数据更新 支持定时刷新(每日零点)与手动刷新 P0
交互通信 卡片点击触发主体应用打卡操作 P0
多尺寸适配 支持 2×2、2×4 两种尺寸卡片 P1
主题切换 支持亮色/暗色主题自动适配 P2

1.3 预期效果

用户在桌面长按添加卡片后,将看到以下效果:

┌─────────────────────────┐
│  📅 每日打卡            │
│  ─────────────────────  │
│  已连续打卡: 28 天       │
│  今日状态: ✅ 已完成     │
│  ─────────────────────  │
│  [立即打卡]  [查看详情]  │
└─────────────────────────┘

卡片每日零点自动刷新数据,点击"立即打卡"按钮可触发打卡操作并更新显示。

1.4 技术挑战

开发过程中需要解决以下技术挑战:

  1. 卡片生命周期管理:FormExtensionAbility 的创建、更新、销毁时机
  2. 数据同步机制:卡片与主体应用的数据一致性保障
  3. 跨进程通信:卡片运行在独立进程,如何与主应用通信
  4. 性能优化:卡片刷新频率控制,避免资源浪费
  5. 多尺寸适配:不同尺寸卡片的布局与数据差异化处理

二、数据模型设计

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 动态卡片,原因如下:

  1. 需要支持按钮点击交互
  2. 需要实现状态切换动画效果
  3. 需要局部刷新以提升用户体验
  4. 后续扩展需要更多自定义能力

3.2 卡片与主应用通信方案

方案 原理 优点 缺点 适用场景
FormLink Router 通过 uri 启动 Ability 简单可靠 无法传复杂数据 跳转页面
FormLink Call 调用 Ability 方法 双向通信 需要权限配置 执行操作
DataShare 共享数据存储 数据持久化 需要额外实现 数据同步
CommonEvent 发布订阅事件 松耦合 异步延迟低 事件通知

选型理由:本项目采用 FormLink Call + CommonEvent 组合方案:

  • FormLink Call 用于卡片触发主应用打卡操作
  • CommonEvent 用于主应用通知卡片数据更新

3.3 数据更新策略

策略 实现方式 适用场景
定时更新 form_update_duration 配置 周期性数据刷新
请求更新 updateForm() 主动调用 事件驱动更新
条件更新 网络恢复、应用切换 智能刷新

选型理由:采用混合更新策略:

  1. 配置每日零点定时更新
  2. 用户打卡后主动触发更新
  3. 网络恢复后检查并更新

四、完整代码实现

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.   │  │  │  │渲染器     │  │
│  └───────────┘  │  │  └───────────┘  │
└─────────────────┘  └─────────────────┘

核心机制

  1. 进程隔离:卡片运行在独立沙箱进程,即使崩溃也不影响主应用
  2. 渲染分离:卡片 UI 由 FormRenderer 独立渲染,资源隔离
  3. 数据绑定:通过 FormBindingData 实现数据与 UI 解耦
  4. 安全边界:卡片无法直接访问主应用内存,通过 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 元服务分发链路

元服务从开发到用户桌面的完整链路:

开发者上传 → 应用市场审核 → 云端分发 → 用户搜索/分享 → 免安装加载
                                    ↓
                               桌面卡片 → 服务直达

关键技术环节

  1. 原子化封装:元服务独立打包,最小化体积
  2. 签名校验:多层签名验证确保完整性
  3. 按需加载:先加载核心代码,资源懒加载
  4. 缓存策略:已使用元服务本地缓存
  5. 跨设备流转:分布式数据同步

六、常见问题解答

Q1: 卡片不显示或显示空白?

原因分析

  • form_config.json 配置错误
  • ArkTS 卡片文件路径不正确
  • 卡片组件编译失败

解决方案

  1. 检查 module.json5 中 metadata 引用的配置文件
  2. 确认卡片源文件路径与配置一致
  3. 查看 DevEco Studio 编译输出日志
  4. 确保卡片组件使用 @Entry 装饰器

Q2: 卡片刷新不生效?

原因分析

  • updateForm 未正确调用
  • FormBindingData 数据格式错误
  • 系统限制刷新频率

解决方案

  1. 检查 updateForm 回调是否返回有效数据
  2. 确认数据字段名与卡片组件绑定一致
  3. 避免短时间频繁调用 updateForm
  4. 检查后台任务是否被系统回收

Q3: 卡片点击无响应?

原因分析

  • postCardAction 参数错误
  • 目标 Ability 未正确配置
  • 权限不足

解决方案

  1. 确认 action 参数使用正确(router/call/message)
  2. 检查目标 Ability 是否在 module.json5 声明
  3. 查看 HiLog 日志确认事件是否触发
  4. 验证 form_config.json 中的 ability 配置

Q4: 如何实现卡片深色模式适配?

解决方案

  1. 在 form_config.json 设置 "colorMode": "auto"
  2. 使用系统资源 $r('sys.color.xxx') 自动适配
  3. 在卡片组件中监听系统主题变化
@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 性能优化进阶

深入优化卡片性能:

  • 增量更新机制减少数据传输
  • 图片资源按需加载与缓存
  • 复杂动画降级策略

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐