Kotlin Multiplatform for OpenHarmony 实战:KStateMachine 有限状态机适配

本文是 KMP 三方库鸿蒙化适配,聚焦
KStateMachine(Kotlin 轻量有限状态机)的 OpenHarmony 适配。我们只讲本仓库真实落地的代码,不做系列横向对比。
摘要
本文记录 KStateMachine(Kotlin 轻量有限状态机)在 OpenHarmony 上的真实适配过程。核心思路是桥接型三层架构:语义层用纯 ArkTS 复刻状态机契约(State / Event / Transition + Guard),引擎层桥接 @kit.ArkData 的 Preferences 做同步持久化,验收页驱动订单状态机验证「守卫拒绝、合法转移、杀进程恢复」三条主链路。文中还总结了 ArkTS 严格模式下的四个踩坑点(具名接口、Context 注入、同步 API、Toggle 开关)。
目录
- 一、为什么选它
- 二、适配总思路:三层架构(桥接型)
- 三、语义层:State / Event / Transition + Guard
- 四、引擎层:桥 Preferences 持久化
- 五、验收页:真机上验证
- 六、踩坑小结
- 社区引导
一、为什么选它
KStateMachine 用声明式方式建模「状态 / 事件 / 转移」,并支持守卫(guard)——只有条件满足才允许转移。它非常适合订单流转、登录流程、设备连接等强状态场景,也是 Kotlin 生态里比 Decompose 更轻的状态建模工具(Decompose 偏组件树,KStateMachine 偏状态本身)。
到了 OpenHarmony,状态机本身是纯算法,但「状态变更后落盘、进程被杀再恢复」是真实需求。所以我们采用桥接型适配:语义层纯 ArkTS 复刻状态机契约,引擎层桥 @kit.ArkData 的 Preferences 做持久化——既还原 Kotlin 语义,又落地了鸿蒙真实能力。
二、适配总思路:三层架构(桥接型)
- 语义层(零
@kit.*):StateConfig/StateMachine描述状态与转移,send(event)执行合法性 + 守卫校验。 - 引擎层(桥
@kit.ArkData):OhosStateMachineEngine把当前状态saveState到 Preferences(同步落盘)并loadState恢复。 - 验收页:
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(),按最简路径重放恢复到上次状态(演示进程重建后状态不丢)。
运行一遍,状态卡会随按钮正确迁移,并可在「杀进程再进」后看到状态被还原。


六、踩坑小结
- 守卫上下文用具名接口:
GuardContext { authenticated: boolean }而非对象字面量类型,避免arkts-no-untyped-obj-literals。 Context由页面注入:引擎层构造函数收common.Context,禁止模块顶层getContext。- Preferences 用同步 API:
getPreferencesSync/putSync/flushSync,比 RdbStore 的 Promise 更轻,适配状态小键值正合适。 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
更多推荐



所有评论(0)