请添加图片描述

1. 前言

上一篇,我们把阳台上的薄荷放进了一张2×2桌面卡片。普通态显示植物名、最近观察和日记入口;点一下花盆,激活态里的瓢虫从叶后探出来。两套界面使用相同的植物身份与本地资源,页面先加载,观察资料随后补齐。

现在给它增加一个动作:摇动手机,也能唤醒瓢虫。

用户眼中的变化很小。手指不必碰到花盆,多了一个与卡片打招呼的方式。代码却需要回答一个新的问题:提供方收到回调时,怎样知道这次应该播放动效?

可以把期望写成三个操作。点击花盆,尝试动效;摇动手机,尝试动效;在应用里更新观察,卡片显示新摘要。第三个操作尤其重要。用户记录“新长出两片叶子”,并不意味着他同时要求瓢虫出来走一圈。

请添加图片描述

本文继续使用薄荷 plant-001,保留 MintCard 和 MintLive 两个页面。观察日记仍由用户手动维护。摇动不会登记浇水,也不会改变植物的生长状态。我们要增加的是一个触发入口,而它应当准确表达用户的动作。

2. 方案

处理事件时,我习惯先问两个问题:事件从哪里到达,它允许程序做什么?这两个答案有时相同,有时需要额外信息才能建立联系。

onUpdateForm 就属于后一种情况。按照ArkTS卡片生命周期的说明,它还用于定时、定点及使用方主动更新等场景。因此,进入这个函数只能说明发生了相应的更新回调,不能单独证明用户摇动了手机。

如果在函数入口直接请求动画,代码会非常短。但这段代码也把一个假设藏了起来:所有更新都代表摇动。摘要刷新一旦走到这里,假设便变成用户看得见的行为。

我们需要把三条路径分别写清楚。

输入接入路径应用职责
点击花盆卡片发送 message,提供方接收 onFormEvent识别动效消息,发起请求
系统摇动配置 shake,由系统参与识别与调度依据正式来源机制分发请求
普通更新对应的内容更新流程读取并更新卡片内容

互动卡片开发的摇动流程涉及 onUpdateForm 和提供方请求激活。这意味着添加配置之后,仍要处理应用侧的分发;也意味着来源判断必须参考完整接口,不能仅凭流程图推测回调参数。

请添加图片描述

这个区别适合收在一个很小的接入层里。它负责把系统事件解释成应用可以理解的输入;后面的代码只决定是否请求动效。这样,SDK参数的变化不会散落到页面、数据读取和动画逻辑中。

两种动效入口则应尽早汇合。它们打开同一个 MintLive,使用同一盆薄荷和同一套加载逻辑。为摇动另建一个页面,会多出一套需要同步维护的植物名、花盆位置和缺省状态,当前需求并不需要这种分叉。

日记按钮仍保留独立的业务入口,目标是 plant-001。点击动效区域与点击日记按钮表达不同意图;判断消息时,应当保留这种区别。

3. 实现

先看版本。场景动效基础配置从API20已有;本篇使用的 triggerTypes 中的 shake 从26.0.0开始支持。基础能力与新增入口需要分别记录,排查兼容性时才能找到正确的检查点。

配置或能力版本边界本篇用途
sceneAnimationParamsAPI20已有声明场景动效配置
abilityName场景动效基础配置项引用激活扩展
triggerTypes 中的 shakeAPI26增量接入系统摇动触发

设备能显示普通卡片,并不能据此推出它支持场景动效或摇动入口。

第01篇的 sceneAnimationParams 已经指向 MintLiveAbility。现在将以下片段合入既有卡片定义:

{
  "sceneAnimationParams": {
    "abilityName": "MintLiveAbility",
    "triggerTypes": ["shake"]
  }
}

这里新增的只有 triggerTypes。普通扩展仍叫 MintFormAbility,激活扩展仍叫 MintLiveAbility,模块声明中的扩展名称必须与引用一致。卡片标识、2×2规格和页面名称都沿用上一版。

也不要同时加入 funInteractionParams。两类配置同时存在会影响系统对卡片类型的识别。小花园使用的是场景动效,后续请求与生命周期讨论都建立在这一点上。

请添加图片描述

配置之后,最容易仓促完成的部分是来源识别。这里需要核对当前SDK的 FormExtensionAbility、相关 FormParam 文档与完整官方样例,确认正式参数、来源语义和支持版本。现有流程资料没有给出完整判别逻辑,因此本文不指定某个Want键来代表摇动。

这个接口细节可以与应用的决策规则分开。下面先定义接入层输出的应用类型。枚举名称由项目定义,不对应SDK字段。

enum MintInput {
  AnimationClick,
  SystemShake,
  ContentRefresh,
  Unclassified
}

function shouldRequestAnimation(input: MintInput): boolean {
  return input === MintInput.AnimationClick ||
    input === MintInput.SystemShake;
}

这段函数有一个容易检查的性质:只有两类明确输入能申请动效。普通刷新与无法分类的事件都不会被升级成摇动。Unclassified 还提醒调用者,无法判断与已经确认普通刷新是两种状态。

它只决定动效请求,不决定全部业务处理。普通更新仍应完成原有数据刷新职责,来源识别失败也不应顺手切断已有的内容更新流程。把函数命名为 shouldRequestAnimation,比笼统的 handleEvent 更能限制它承担的责任。

点击入口相对直接。卡片与提供方可以约定一个应用消息名,识别时只接受该消息。下面的类型和函数位于消息已经按项目协议解析、校验之后:

interface MintMessage {
  action: string;
}

function classifyMintMessage(message: MintMessage): MintInput {
  if (message.action === 'playMintAnimation') {
    return MintInput.AnimationClick;
  }
  return MintInput.Unclassified;
}

playMintAnimation 是小花园自己的协议值。其他卡片消息不会因为进入 onFormEvent 就自动获得播放动画的含义;消息解析失败时也应记录原因,而不是填入默认的动效动作。

摇动接入层要遵循同样的规则:只有正式机制确认的来源,才能产生 SystemShake。人工观察到“刚才摇了手机”,或者日志恰好出现 onUpdateForm,都不能代替程序里的来源判别。这个映射是接入前必须完成的核验项,应用枚举本身不会补上缺失的系统证据。

请添加图片描述

通过判断后,点击和摇动都交给已有的动效请求逻辑,接入 requestOverflow。当前卡片实例使用 formId 标识,植物对象使用 plantId 标识;不能因为只有一盆薄荷就把两者互换。

激活页面继续遵守上一篇的加载顺序。以下是 onLiveFormCreate 同步路径中的关键调用,存储项已在调用前准备好:

session.loadContent('pages/MintLive', initialStorage);

loadSnapshot('plant-001')
  .then(applySnapshot)
  .catch(showReadFailure);

其中数据读取与更新函数沿用项目封装。增加入口不应改变页面何时出现,也不应让摇动路径重新等待业务资料。单次场景动效申请仍不超过3500ms,并且允许被提前中断。

请求失败时,保留返回信息和当前上下文即可,不循环重试到成功。普通卡片仍应显示摘要、提供日记入口。为了补偿摇动没有触发而在后台持续监听加速度,会引入另一套识别与生命周期问题,也无法证明系统摇动入口已经正确接入。

4. 检验

一个入口是否正确,既要检查它该做的事,也要检查它不该做的事。对小花园来说,点击和摇动能否进入激活UI是一半;普通刷新是否保持安静是另一半。

可以先检查应用规则。下面的检查只验证分发函数,不涉及系统是否识别摇动:

function checkAnimationPolicy(): void {
  if (!shouldRequestAnimation(MintInput.AnimationClick)) {
    throw new Error('Click should request animation');
  }
  if (!shouldRequestAnimation(MintInput.SystemShake)) {
    throw new Error('Shake should request animation');
  }
  if (shouldRequestAnimation(MintInput.ContentRefresh)) {
    throw new Error('Refresh must not request animation');
  }
  if (shouldRequestAnimation(MintInput.Unclassified)) {
    throw new Error('Unknown input must not request animation');
  }
}

这里的覆盖范围很小,但边界明确。即使四项检查成立,也只能说明应用规则符合预期,系统事件到枚举值的映射仍须单独验证。

真机对照准备A、B两组配置:A保留第01篇配置,B增加 shake。完成来源处理后,两组使用相同代码、资源与数据,只保留配置差异。记录机型、系统、SDK、工具版本和构建编号,不能把换设备后的行为差异归因于一行配置。

每个用例重复三次,分别保存日志和录屏。先确认卡片状态,再开始记录、执行操作,等待动效退出或观察结束,最后核对摘要与日记。普通更新和摇动分开执行,否则一次相邻的回调很容易被错误归因。

用例核对重点实际记录
点击花盆消息是否正确分类,是否请求并显示激活UI待采集
单次摇动正式来源证据、请求结果、A/B表现待采集
连续摇动事件、请求与会话的对应关系待采集
普通更新摘要更新,未被误分发为动效待采集
卡片不在当前桌面实际回调、呈现情况及返回后的内容待采集
请求失败诊断信息、普通态内容与日记可用性待采集
旧系统分别记录普通卡片、点击动效、摇动能力待采集

普通更新用例尤其需要写清触发方法。onUpdateForm 是提供方回调,数据回推又是另一个操作。仅调用一次数据更新方法,没有观察到目标回调,不能声称已经覆盖了“更新回调误触发动效”的风险。

请添加图片描述

日志应同时保留人工操作与程序判断。人工操作回答“做了什么”,来源证据回答“程序依据什么分类”。可以采用下面的记录结构,空位由实际采集填入:

env: device=... os=... sdk=... build=... variant=...
context: formId=... plantId=plant-001 operationId=...
operation: kind=... time=...
callback: name=... time=... sourceEvidence=...
decision: input=... requestAnimation=...
request: time=... result=...
lifecycle: event=... time=...
video: file=... visibleFrame=...

operationId 是应用侧关联记录的编号,不是系统参数。一次操作可能对应多个事件,连续摇动也未必逐次产生独立激活。先保留对应关系,再解释原因,不预设系统会排队或每次都会响应。

观察结果还要分层。来源正确,说明分类有依据;请求成功,说明请求阶段返回了成功;创建回调出现,说明生命周期走到了相应位置。屏幕是否显示薄荷、动画是否完整播放,需要录屏提供另外的证据。

请添加图片描述

旧系统与不在当前桌面的用例也按这一方法记录,不提前填写错误码。缺少对应设备时保留覆盖缺口。真正有用的结果是“在哪个环境、执行什么操作、得到哪些事件与画面”,而不是脱离条件的一句“摇一摇正常”。

5. 结尾

摇动入口的配置只有一行,正确接入却需要明确的事件语义。点击消息、系统摇动和普通更新可以经过相近的处理位置,但应用必须保留它们各自的含义。

这篇整理出的版本表、配置差异、触发图、分发规则与验证矩阵,共同约束一个行为:只有明确的动效输入才发起请求。正式来源映射完成核验后,还应结合日志与录屏确认整条路径,尤其检查普通更新是否被误触发。

下一篇继续使用同一个 MintLive 和薄荷 plant-001,在可靠的激活路径上处理区域控制:叶片伸出边框时,花盆怎样仍留在原来的位置。

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐