用户根本不会打开你的应用

做过一个天气类元服务,上线前的数据很打脸:日活里七成用户只看桌面卡片,从来不点进应用。那一刻我意识到,卡片不是应用的广告位,卡片就是产品本体。既然如此,卡片的刷新、交互、跳转每一环都得认真对待,这篇文章把这些环节逐一拆开。

卡片和应用是两个世界

先建立一个关键认知:卡片运行在独立的渲染进程里,和你的应用主进程不是一回事。所以卡片里不能用应用内的 router,不能直接访问应用的内存数据,甚至 ArkUI 里不少能力在卡片侧是阉割的。卡片的点击用 postCardAction 表达意图,数据由系统把应用侧提供的内容定时灌进来。想明白这个隔离,后面很多“为什么不行”就有了答案。

卡片的生命周期与数据供给

卡片的宿主是 FormExtensionAbility,添加、更新、销毁都走它的回调。

import { FormExtensionAbility, formBindingData, formInfo } from '@kit.FormKit';
import { Want } from '@kit.AbilityKit';
import { hilog } from '@kit.PerformanceAnalysisKit';

export default class WeatherFormAbility extends FormExtensionAbility {
  // 用户把卡片添加到桌面时触发,返回的数据就是卡片首次显示的内容
  onAddForm(want: Want): formBindingData.FormBindingData {
    const formId = want.parameters?.[formInfo.FormParam.IDENTITY_KEY] as string;
    // formId 要自己存起来,之后更新全靠它
    return formBindingData.createFormBindingData({
      city: '杭州', temp: '26°', formId: formId
    });
  }

  // 系统按配置的定时策略触发更新
  onUpdateForm(formId: string): void {
    const data = formBindingData.createFormBindingData({
      city: '杭州', temp: '25°'
    });
    formProvider.updateForm(formId, data);
  }
}

onAddForm 返回的绑定数据直接决定卡片初始显示,formId 是这张卡片的唯一身份,更新时必须拿着它说话。最常见的错误就是没存 formId,导致后面想主动刷新时两眼一抹黑,本地数据库里务必留一张卡片注册表。

点击跳转与参数透传

卡片侧的点击能力由 postCardAction 提供,它有三种动作:跳转应用、拉起后台能力、发消息给 FormExtensionAbility。

// 卡片 ArkTS 里(卡片是 @Entry 的独立 struct)
postCardAction(this, {
  action: 'router',
  abilityName: 'EntryAbility',
  params: { target: 'cityDetail', cityId: 3301 }
});

应用侧在 onNewWant 里接参数。注意卡片冷启动和热启动走的是不同的回调:应用没起来时参数进 onCreate 的 want,应用在后台时进 onNewWant,两处都要接,漏一处就会出现“点卡片偶尔没反应”的疑难杂症。

import { UIAbility, AbilityConstant, Want } from '@kit.AbilityKit';

onNewWant(want: Want, launchParam: AbilityConstant.LaunchParam): void {
  const target = want.parameters?.target as string;
  if (target === 'cityDetail') {
    const cityId = want.parameters?.cityId as number;
    // 跳转到对应城市页
  }
}

刷新策略要省着用

卡片的定时刷新通过配置文件的 scheduledUpdateTime 和 updateDuration 设置,但系统对刷新频率有严格管控,最小粒度是半小时级别,想秒级刷新是不可能的,也不该可能——想想桌面上几十张卡片一起飙更新的电量灾难。频控之内能做的事:把更新时机对齐业务,比如天气卡片定在整点后几分钟更新,正好赶上数据源出数;主动刷新留给关键时刻,比如下单成功后立刻更新订单卡片,这种用 formProvider.updateForm 主动推。

数据一致性别掉链子

卡片显示的数据和应用内的数据可能不同步,用户在应用里改了城市,卡片还显示旧的。解法是单向同步:应用内数据变化时,负责查出该用户所有活跃卡片的 formId,逐个推送更新。别指望卡片自己发现数据变了,它没有这个能力,同步的发起方永远是应用侧。

写在最后

总结成几句实在话:卡片是独立进程,交互靠 postCardAction,数据靠 FormExtensionAbility 供给和 updateForm 推送;formId 从添加那一刻就要存好;跳转参数冷热两条路都要接;刷新频控之内做文章,别想着绕。把卡片当成一个独立产品去打磨,而不是应用的缩略图,元服务的留存数据会用增长回报这个认知。

Logo

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

更多推荐