一、场景介绍:为什么需要卡片刷新消息?

想想看,你有没有遇到过这种情况:想随时查看天气却得打开天气 APP,想看新闻更新还得点开新闻软件,这些繁琐的操作是不是很影响体验?HarmonyOS 推出的 Form Kit(卡片开发服务)就是来解决这个问题的 —— 它能把应用的重要信息或操作直接前置到桌面卡片上,让你不用打开应用就能获取关键信息。

而针对那些需要实时更新数据的卡片,比如实时天气、股票行情、外卖进度这类场景,Push Kit 提供的卡片刷新服务就派上用场了。简单来说,只要你的应用集成了 Push Kit,拿到 Push Token,就能通过系统级通道给用户推送卡片更新内容,用户感知更及时,自然也就更愿意用你的应用啦。

重点总结:

  1. Form Kit 让应用信息前置到桌面,减少用户操作层级
  2. Push Kit 提供卡片刷新服务,适合实时数据更新场景
  3. 集成 Push Kit 获取 Token 后,可通过系统通道推送更新

二、频控规则:发消息可不能太 "任性"

这里得先给开发者划重点:推送消息可不是想发多少就发多少,华为对推送频率做了明确限制,既能保证用户体验,也能避免被当成骚扰信息。

测试阶段(调测时)

每个项目每天全网最多只能发 1000 条测试消息,而且发送时必须把 testMessage 设为 true。记住哦,这是测试阶段的 "额度",可别超了。

正式发布阶段

  • 单设备单应用总限制: 每天所有场景化消息加起来不能超过 3000 条
  • 单张卡片限制: 这得看应用是否上架
    • 已上架应用:单设备单应用下,单张卡片每天只能发 2 条刷新消息
    • 未上架应用:稍微宽松点,单张卡片每天能发 5 条

特别提醒

不管是测试消息还是正式消息,单次发送只能携带一个 Token,可别想着 "批量操作" 哦。

重点总结:

  1. 测试阶段:每日 1000 条测试消息,需设置 testMessage=true
  2. 正式阶段:单设备单应用每日总消息≤3000 条
  3. 单张卡片:已上架每日 2 条,未上架每日 5 条
  4. 单次推送仅支持 1 个 Token

三、开发步骤:从零开始实现卡片刷新

(一)开发卡片:先把 "舞台" 搭好

要实现卡片刷新,得先把本地卡片开发好。这里分三步走,每一步都有对应的代码配置,咱们一步步来。

1. 创建 ArkTS 卡片

首先得创建一个基础的 ArkTS 卡片,这是卡片的 "骨架"。具体怎么创建呢?可以参考华为官方文档里 "创建一个 ArkTS 卡片" 的步骤,这里就不重复啦。

2. 配置 form_config.json

在项目模块的 src/main/resources/base/profile/form_config.json 里,有个关键配置:把 dataProxyEnabled 字段设为 true,这相当于开启了卡片的 "刷新开关"。来看具体配置示例:

{
  "forms": [
    {
      "name": "widget",
      "src": "./ets/widget/pages/WidgetCard.ets",
      "uiSyntax": "arkts",
      "window": {
        "designWidth": 720,
        "autoDesignWidth": true
      },
      "colorMode": "auto",
      "isDefault": true,
      "updateEnabled": true,
      "updateDuration": 1,
      "scheduledUpdateTime": "10:30",
      "defaultDimension": "2*2",
      "supportDimensions": ["2*2"],
      "dataProxyEnabled": true  // 关键配置,开启卡片代理刷新功能
    }
  ]
}

3. 获取 formId 并定义刷新字段

在卡片生命周期管理文件(比如 EntryFormAbility)的 onAddForm () 回调里,需要做两件事:获取 formId,定义要刷新的字段。以 text_key 和 image_key 为例,来看代码:

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

export default class EntryFormAbility extends FormExtensionAbility {
  onAddForm(want: Want): formBindingData.FormBindingData {
    // 获取formId,这是卡片的唯一标识
    const formId = want.parameters![formInfo.FormParam.IDENTITY_KEY] as string;
    
    // 定义需要在卡片页面中刷新的字段
    class CreateFormData {
      formId: string = '';
      text_key: string = '';
      image_key: string = '';
    }
    const obj: CreateFormData = {
      formId: formId,
      text_key: '默认文本',
      image_key: ''
    }
    
    // 创建绑定数据
    const bindingData: formBindingData.FormBindingData = formBindingData.createFormBindingData(obj);
    
    // 定义需要通过Push Kit代理刷新的字段,每个key都要在bindingData中定义
    const text_key: formBindingData.ProxyData = {
      key: 'text_key',
      subscriberId: formId
    };
    const image_key: formBindingData.ProxyData = {
      key: 'image_key',
      subscriberId: formId
    };
    
    bindingData.proxies = [text_key, image_key];
    return bindingData;
  }
}

4. 卡片页面数据绑定

在卡片页面文件(比如 WidgetCard.ets)中,需要创建 LocalStorage 变量并绑定数据。这里要注意:图片组件传递的变量必须以 memory:// 开头。来看具体实现:

// 定义页面级的UI状态存储LocalStorage
const storage = new LocalStorage();
// 绑定
@Entry(storage)
@Component
struct WidgetCard {
  @LocalStorageProp('formId') formId: string = '';
  @LocalStorageProp('text_key') text: string = '';
  @LocalStorageProp('image_key') image: string = '';
  
  build() {
    Flex({ direction: FlexDirection.Column }) {
      Row() {
        Text() {
          // Span是Text组件的子组件,用于显示行内文本
          Span('formID:')
          Span(this.formId)
        }
        .fontSize(10)
      }
      Row() {
        Text() {
          Span('文本:')
          Span(this.text)
        }
        .fontSize(10)
      }
      Row() {
        if (this.image) {
          Image('memory://' + this.image).height(80)  // 图片路径必须以memory://开头
        }
      }
    }
    .padding(10)
    .onClick(() => {
      postCardAction(this, {
        action: 'router',
        abilityName: 'MainAbility', // 请配置为应用实际的abilityName
      });
    })
  }
}

开发卡片重点总结:

  1. 配置 form_config.json 开启 dataProxyEnabled=true
  2. 在 onAddForm () 中获取 formId 并定义刷新字段(text_key/image_key)
  3. 使用 LocalStorageProp 绑定页面数据,图片路径需以 memory:// 开头

(二)推送卡片刷新消息:让数据 "动" 起来

卡片开发好了,接下来就是关键的推送环节。这一步需要分三步走:获取 Push Token、上报信息到服务端、调用 REST API 推送消息。

1. 获取 Push Token

首先得获取 Push Token,这是推送消息的 "通行证"。可以参考华为文档中 "获取 Push Token" 的指导,这里给出获取 Token 的代码示例:

import { pushService } from '@kit.PushKit';

async function getPushToken() {
  try {
    const pushToken: string = await pushService.getToken();
    return pushToken;
  } catch (err) {
    // 处理获取Token失败的情况
    console.error('获取Push Token失败', err);
  }
}

2. 上报 formId 和 Push Token 到服务端

建议把 formId、pushToken 等信息上报到应用服务端,这样服务端才能知道该给哪个卡片推送消息。来看伪代码实现:

import { Want } from '@kit.AbilityKit';
import { pushService } from '@kit.PushKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { formInfo } from '@kit.FormKit';

async function saveFormInfo(want: Want): Promise<void> {
  try {
    // 获取卡片相关信息
    const formId = want.parameters![formInfo.FormParam.IDENTITY_KEY] as string;
    const moduleName = want.moduleName;
    const abilityName = want.abilityName;
    const formName = want.parameters![formInfo.FormParam.NAME_KEY] as string;
    
    // 获取Push Token
    const pushToken: string = await pushService.getToken();
    
    // 上报到应用服务端
    // 这里需要调用你自己的服务端接口
    await fetch('你的服务端接口地址', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        formId,
        moduleName,
        abilityName,
        formName,
        pushToken
      })
    });
  } catch (err) {
    let e: BusinessError = err as BusinessError;
    hilog.error(0x0000, 'testTag', 'Failed to save form info: %{public}d %{public}s', e.code, e.message);
  }
}

3. 服务端调用 REST API 推送消息

这是最关键的一步,服务端需要构造 HTTP 请求来推送卡片刷新消息。来看完整的请求示例:

// Request URL
POST https://push-api.cloud.huawei.com/v3/[projectId]/messages:send

// Request Header
Content-Type: application/json
Authorization: Bearer eyJr*****OiIx---****.eyJh*****iJodHR--***.QRod*****4Gp---****
push-type: 1  // 1表示服务卡片刷新场景

// Request Body
{
    "payload": {
        "moduleName": "entry",  // 项目模块名,在module.json5中获取
        "abilityName": "EntryFormAbility",  // 服务卡片的ability名称
        "formName": "widget",  // 卡片名称,在form_config.json中定义
        "formId": 423434262,  // 卡片实例ID
        "version": 123456,  // 版本号,必须大于当前版本
        "formData": {
            "text_key": "刷新文本内容"  // 要刷新的文本数据
        },
        "images": [
            {
                "keyName": "image_key",  // 图片控件的key值
                "url": "https://***.png",  // 图片地址
                "require": 1  // 刷新策略:1表示图片失败则不刷新
            }
        ]
    },
    "target": {
        "token": [
            "IQAAAAC*************************dRH7_bPbfMrVfsYw"  // Push Token
        ]
    },
    "pushOptions": {
        "testMessage": true  // 测试消息标识
    }
}

关键参数说明

  • projectId: 登录 AppGallery Connect 获取项目 ID
  • Authorization: JWT 格式的授权字符串,按文档步骤获取
  • version: 必须大于当前卡片刷新消息的版本号,否则刷新失败
  • formData: 对应卡片页面中定义的文本数据字段
  • images: 图片数据,keyName 对应卡片中的 image_key,url 是图片地址
  • require: 图片刷新策略,0 表示图片失败时只刷新文字,1 表示失败则不刷新
  • testMessage: true 表示测试消息,受每日 1000 条限制

推送消息重点总结:

  1. 获取 Push Token 作为推送凭证
  2. 上报 formId 和 Push Token 到服务端
  3. 服务端构造 HTTP 请求,注意各参数含义和格式
  4. version 必须递增,图片格式和大小有限制(PNG/JPG/JPEG,≤512KB,长 * 宽 < 12800 像素)

四、避坑指南:这些细节一定要注意

1. 图片相关限制

  • 禁止推送包含敏感信息的图片
  • 支持格式:PNG、JPG、JPEG
  • 大小限制:单张图片≤512KB
  • 像素限制:长 * 宽 < 12800 像素

2. 版本号 version 的重要性

每次推送的 version 必须比之前的大,不然会刷新失败。这就好比软件更新,必须是更高的版本号才能生效。

3. 测试消息与正式消息的区别

  • 测试消息需要设置 testMessage=true
  • 每个项目每天最多 1000 条测试消息
  • 单次推送只能有一个 Token,正式消息同理

4. 字段对应关系

  • form_config.json 中的 name 对应请求中的 formName
  • module.json5 中的 module 名称对应请求中的 moduleName
  • extensionAbilities 中的 ability 名称对应请求中的 abilityName
  • 卡片页面中定义的 text_key/image_key 对应请求中的 formData/images 字段

五、总结:从原理到实践的全流程回顾

现在咱们来捋一捋整个流程:首先理解为什么需要卡片刷新(提升用户体验和活跃度),然后记住频控规则(测试和正式阶段的限制),接着分两步开发 —— 先搭好卡片 "舞台"(配置文件、获取 formId、绑定数据),再让数据 "动" 起来(获取 Token、上报信息、调用 API 推送)。

整个过程中,代码配置是核心,从 form_config.json 的关键字段到服务端请求的每个参数,都需要一一对应。特别是图片路径的 memory:// 前缀、version 的递增规则、测试消息的标识设置,这些细节很容易出错,一定要多检查。

其实说白了,卡片刷新就是让你的应用能主动把最新信息 "推" 给用户,而不用用户自己打开应用。这就像你有个贴心的小助手,主动把你关心的消息送到眼前,体验自然就上去了。赶紧按照这个步骤试试吧,让你的 HarmonyOS 应用更 "智能"、更懂用户!

Logo

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

更多推荐