在这里插入图片描述

本文是 KMP 三方库鸿蒙化适配,聚焦 KStateMachine(Kotlin 轻量有限状态机)的 OpenHarmony 适配。我们只讲本仓库真实落地的代码,不做系列横向对比。

摘要

本文记录 KStateMachine(Kotlin 轻量有限状态机)在 OpenHarmony 上的真实适配过程。核心思路是桥接型三层架构:语义层用纯 ArkTS 复刻状态机契约(State / Event / Transition + Guard),引擎层桥接 @kit.ArkData 的 Preferences 做同步持久化,验收页驱动订单状态机验证「守卫拒绝、合法转移、杀进程恢复」三条主链路。文中还总结了 ArkTS 严格模式下的四个踩坑点(具名接口、Context 注入、同步 API、Toggle 开关)。

目录

一、为什么选它

KStateMachine 用声明式方式建模「状态 / 事件 / 转移」,并支持守卫(guard)——只有条件满足才允许转移。它非常适合订单流转、登录流程、设备连接等强状态场景,也是 Kotlin 生态里比 Decompose 更轻的状态建模工具(Decompose 偏组件树,KStateMachine 偏状态本身)。

到了 OpenHarmony,状态机本身是纯算法,但「状态变更后落盘、进程被杀再恢复」是真实需求。所以我们采用桥接型适配:语义层纯 ArkTS 复刻状态机契约,引擎层桥 @kit.ArkData 的 Preferences 做持久化——既还原 Kotlin 语义,又落地了鸿蒙真实能力。

二、适配总思路:三层架构(桥接型)

  1. 语义层(零 @kit.*):StateConfig / StateMachine 描述状态与转移,send(event) 执行合法性 + 守卫校验。
  2. 引擎层(桥 @kit.ArkData):OhosStateMachineEngine 把当前状态 saveState 到 Preferences(同步落盘)并 loadState 恢复。
  3. 验收页:KStateMachineDemo 驱动订单状态机,每次合法转移后落盘,页面重建时从 Preferences 恢复。

三、语义层:State / Event / Transition + Guard

StateMachine.ets 零平台依赖(注意 ArkTS 严格模式禁止构造参数属性,字段显式赋值):

export class StateMachine {
  send(event: string, ctx: GuardContext): TransitionResult {
    const defs = this.transitionsOf(this.currentState);
    // 1) 合法性:当前状态是否定义了该 event 的转移
    // 2) 守卫:matched.guard(ctx) 是否为 true
    if (matched.guard !== undefined && !matched.guard(ctx)) {
      return { ok: false, reason: '守卫(guard)未通过,转移被拒绝' };
    }
    this.currentState = matched.target; // 通过则切换
    return { ok: true, reason: '转移成功' };
  }
}

要点:

  • 合法优先于守卫:先查当前状态有没有这个事件,没有就直接报「无合法转移」,再查守卫——与原库行为一致。
  • 守卫上下文:GuardContext 用具名接口(严格模式要求),send('pay', { authenticated: true }) 传参,避免对象字面量类型报错。
  • 历史记录:每次转移追加到 history,验收页可展示完整流转轨迹。

四、引擎层:桥 Preferences 持久化

OhosStateMachineEngine.ets 桥接 OpenHarmony 的 Preferences(同步 API,与 multiplatform-settings 同一套路,无需 async/await):

import { preferences } from '@kit.ArkData';
import { common } from '@kit.AbilityKit';

export class OhosStateMachineEngine {
  saveState(state: string): void {
    const p = preferences.getPreferencesSync(this.ctx, { name: this.storeName });
    p.putSync('current_state', state);
    p.flushSync(); // 同步落盘,进程被杀也能恢复
  }
  loadState(): string | undefined {
    const p = preferences.getPreferencesSync(this.ctx, { name: this.storeName });
    return p.getSync('current_state', undefined) as string | undefined;
  }
}

Context 由页面 this.getUIContext().getHostContext() 注入(严格模式禁止模块顶层取),保证引擎层只持有合法上下文。

五、验收页:真机上验证

本项目开发代码如下:
在这里插入图片描述
KStateMachineDemo.ets 用订单状态机演示:

  • 支付守卫:顶部开关控制「账户已认证」。未认证时点「支付」→ 守卫拒绝,状态保持「待支付」;认证后再点 → 转移到「已支付」。
  • 合法转移:已支付 → 发货 → 已发货 → 送达 → 已完成,每步状态正确演进。
  • 持久化恢复:每次合法转移后 engine.saveState(...) 落盘;页面 aboutToAppear 调 loadState(),按最简路径重放恢复到上次状态(演示进程重建后状态不丢)。

运行一遍,状态卡会随按钮正确迁移,并可在「杀进程再进」后看到状态被还原。
在这里插入图片描述
在这里插入图片描述

六、踩坑小结

  1. 守卫上下文用具名接口:GuardContext { authenticated: boolean } 而非对象字面量类型,避免 arkts-no-untyped-obj-literals。
  2. Context 由页面注入:引擎层构造函数收 common.Context,禁止模块顶层 getContext。
  3. Preferences 用同步 API:getPreferencesSync / putSync / flushSync,比 RdbStore 的 Promise 更轻,适配状态小键值正合适。
  4. Toggle 开关:用 ToggleType.Switch 表达守卫布尔量,比手写按钮更直观。

社区引导

欢迎加入 KMP&CMP 鸿蒙社区:https://atomgit.com/CPF-KMP-CMP

本适配全部源码已开源在 AtomGit:https://atomgit.com/wdracky/kmp-ohos-adapters/tree/main/kstatemachine

如果你在适配过程中用到了 AI 辅助工具,推荐码道(AtomCode)专属通道
https://developer.huaweicloud.com/codeartsco.html?source=dmzntgwatomgit1&sourcead=dmzntgwatomgiths

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐