HarmonyOS 鸿蒙Next中关于服务卡片更换关联实体、保活的问题

HarmonyOS 鸿蒙Next中关于服务卡片更换关联实体、保活的问题 我目前在将Home Asistant伴侣 APP 迁移到鸿蒙next,但是遇到了一些卡片开发的问题。我无法完全照搬安卓小部件的实现。现在遇到的问题:1、APP对应的卡片进程很容死掉。2、更换关联实体逻辑搞不清楚,虽然可以更换关联实体但是不能立马生效需要在选择完实体以后等待2-3秒后才能生效,这体验很不好。3、卡片的状态从用户服务器同步状态,简直完全搞不清楚逻辑。

我的希望官方开发者或者自由开发者能给我一个智慧生活卡片样例,最好有卡片保活、同步状态、更换关联实体等例子谢谢。

4 回复

尊敬的开发者您好:

FormExtensionAbility进程不能常驻后台,即在卡片生命周期回调函数中无法处理长时间的任务,在生命周期调度完成后会继续存在10秒,如10秒内没有新的生命周期回调触发则进程自动退出。针对可能需要10秒以上才能完成的业务逻辑,建议拉起主应用进行处理,处理完成后使用updateForm通知卡片进行刷新。

服务卡片配置被动刷新时,如果采用定时刷新,最小刷新时间间隔为30分钟;目前也可以在服务卡片中实现分钟级刷新的效果,您可参考:

【背景知识】

  • Form Kit(卡片开发框架)提供了一种在桌面、锁屏等系统应用上嵌入显示应用信息的开发框架和API,可以将应用内用户关注的重要信息或常用操作抽取到服务卡片(简称“卡片”)上,通过将卡片添加到桌面、锁屏等系统应用上,以达到信息展示、服务直达的便捷体验效果。
  • ArkTS卡片被动刷新:
    • 定时刷新:表示在一定时间间隔内调用onUpdateForm的生命周期回调函数自动刷新卡片内容。定时刷新有配额限制,每张卡片每天最多通过定时方式触发刷新50次。
    • 定点刷新:表示在每天的某个特定时间点自动刷新卡片内容,最多可设置24个时间。
  • TextClock组件通过文本将当前系统时间显示在设备上。从API version 11开始,该组件支持在ArkTS卡片中使用。当时间变化时,会触发onDateChange回调,组件不可见时不回调。卡片中使用时,该事件回调间隔为分钟。

【解决方案】

由于卡片被动刷新的次数有限,无法直接在服务卡片上实现分钟级刷新的效果。如果引入TextClock组件后,可通过onDateChange回调函数间接实现服务卡片刷新。

示例卡片采用动态时间显示(每分钟刷新并记录日志)和模拟时钟指针旋转(每次刷新旋转30度),同时实时展示刷新次数统计。示例代码如下:

@Entry
@Component
struct DiawidgetCard {
  @State num: number = 0; // 记录刷新次数

  build() {
    Column() {
      Text(`当前刷新次数为:${this.num}`);
      TextClock()
        .onDateChange((value: number) => {
          const unixTimestamp = value;
          const milliseconds = unixTimestamp * 1000; // 转换为毫秒
          const date = new Date(milliseconds);
          // 获取时间各部分
          const year = date.getFullYear(); // 年份
          const month = date.getMonth() + 1; // 月份(0-11→1-12)
          const day = date.getDate(); // 日期
          const hours = date.getHours(); // 小时
          const minutes = date.getMinutes(); // 分钟
          console.info('当前卡片时间更新为', `${year}-${month}-${day} ${hours}:${minutes}`);
          this.num++;
        })
        // 用于控制组件是否展示
        .visibility(Visibility.Visible);
      Stack() {
        Image($r('sys.media.ohos_ic_public_clock')) // 'sys.media.ohos_ic_public_clock'仅作示例,请替换为实际使用的资源
          .width(100)
          .offset({
            x: -1,
            y: 20
          });
        Row()
          .rotate({
            x: 0,
            y: 0,
            z: 1,
            centerX: '0%',
            centerY: '100%',
            angle: this.num * 30
          })
          .width(2).height(40).backgroundColor(Color.Black);
      };
    }
    .width('100%')
    .height('100%');
  }
}

更多卡片相关DEMO您可参考:实现卡片更新与数据交互功能基于Form Kit实现音乐服务卡片

更多关于HarmonyOS 鸿蒙Next中关于服务卡片更换关联实体、保活的问题的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


看到文档了,生命周期完成最多活10秒 :(

当UIAbility死了,没有长任务。也能让用户看见卡片显示的实时数据。默认的30分钟,太不友好了吧。

在鸿蒙Next中,更换服务卡片关联实体需通过FormExtensionAbilityonUpdateFormonCastToNormalForm接口,利用FormBindingData对象更新数据源或重新绑定Ability。保活方面,可使用BackgroundTaskManager申请长时任务或WorkScheduler实现后台周期性刷新,但系统会基于资源消耗动态管控,无法强制常驻。

对于卡片保活,关键是使用FormExtensionAbility的正确生命周期并绑定持续任务。在卡片提供方的onAddForm中,立即启动一个后台任务(如使用ServiceExtensionAbility或持续任务通知),避免卡片进程被系统回收。核心代码片段:

// FormAbility.ts
import formBindingData from '@ohos.application.formBindingData';
import formProvider from '@ohos.application.formProvider';

export default class EntryFormAbility extends FormExtensionAbility {
  onAddForm(want) {
    let formId = want.parameters["ohos.extra.param.key.form_identity"];
    // 绑定一个后台持续任务来保持进程
    let wantAgentInfo = ...
    // 启动ServiceExtensionAbility,确保进程不死
    startServiceExtensionAbility(wantAgentInfo);
    // 返回初始数据
    return formBindingData.createFormBindingData({ text: "loading..." });
  }
}

更换关联实体不立即生效的核心原因是卡片数据更新依赖系统调度,必须显式调用updateForm强制刷新。在用户选择实体后,不要依赖自动更新,而是立即构造新数据并调用formProvider.updateForm

// 在页面选择实体后
let updateData = formBindingData.createFormBindingData({ 
  entityId: selectedEntityId,
  state: "on" 
});
formProvider.updateForm(formId, updateData).then(() => {
  console.log('卡片立即更新');
});

状态同步的逻辑其实是在卡片提供方(FormExtension)的onUpdateForm或后台常驻任务中定时拉取服务器状态,再调用updateForm推送至卡片。为了实现实时更新,可在onAddForm时启动一个定时器或监听回调,将最新实体状态通过formBindingData推送到所有相关卡片:

// 定时同步示例(在ServiceAbility中)
setInterval(async () => {
  let state = await fetchEntityStateFromServer(entityId);
  let data = formBindingData.createFormBindingData(state);
  formProvider.updateForm(formId, data);
}, 30000);

以上三个核心点配合即可实现智慧生活卡片的需求。整个卡片的保活、实体联动和状态同步,均围绕formProvider.updateForm做即时更新,并通过后台任务维持进程。

回到顶部