
摘要
本文记录 kotlinx.coroutines(Kotlin 官方协程库)在 OpenHarmony 上的真实适配过程。核心思路是语义等价复刻 :ArkTS 本身是单线程异步模型(事件循环 + Promise),与 Kotlin 协程"挂起不阻塞线程"的心智完全同构,因此无需重写协程运行时,只需用 ArkTS 原生 Promise 承载挂起/并发语义,把 API 形状与原库对齐。全文按三层架构展开:语义层(Coroutines.ets 定义 CoroutineScope / Job / Deferred<T>)、引擎层(OhosCoroutinesEngine 桥接调度与挂起)、验收页(真机验证并发 launch、async/await、withContext)。文末附踩坑小结与开源地址。
目录
- 一、为什么选它
- 二、适配总思路:三层架构
- 三、语义层:结构化并发的核心类型
- [四、引擎层:桥 ArkTS 异步运行时](#四、引擎层:桥 ArkTS 异步运行时)
- 五、验收页:真机上验证
- 六、踩坑小结
- 社区引导
一、为什么选它
kotlinx.coroutines 是 Kotlin 官方协程库,提供 CoroutineScope / launch / async / Deferred / Dispatchers / withContext 等"结构化并发"原语,是 KMP 异步代码的基石。
到了 OpenHarmony,ArkTS 本身是单线程异步模型 (事件循环 + Promise),这与 Kotlin 协程"主线程非阻塞、挂起不阻塞线程"的核心心智完全同构 。因此协程在鸿蒙上的适配,不是去"重写一个协程运行时",而是做语义等价复刻 :用 ArkTS 原生 Promise 承载挂起/并发语义,把 API 形状与原库对齐。这与本系列 Decompose(纯状态管理等价复刻)是同一思路。
二、适配总思路:三层架构
- 语义层(不碰
@kit.*) :定义DispatcherName/Job/Deferred<T>/CoroutineScope,用Promise承载并发。 - 引擎层(桥 ArkTS 异步运行时) :
OhosCoroutinesEngine提供mainScope/withContext/delay,把调度与挂起交给系统。 - 验收页 :
CoroutinesDemo在真机/模拟器上跑并发 launch、async/await、withContext。
三、语义层:结构化并发的核心类型
Coroutines.ets 只定义类型与逻辑,零平台依赖(注意 ArkTS 严格模式禁止构造参数属性):
typescript
export class CoroutineScope {
launch(block: () => void | Promise<void>): Job {
const job = new Job();
Promise.resolve().then(() => Promise.resolve(block()))
.then(() => job.markDone());
return job;
}
asyncTask<T>(block: () => T | Promise<T>): Deferred<T> {
const job = new Job();
const promise = Promise.resolve().then(() => Promise.resolve(block()));
return new Deferred(promise.then(v => { job.markDone(); return v; }), job);
}
}
launch 返回 Job、asyncTask 返回 Deferred<T>(其 awaitValue() 返回 Promise<T>),与原库契约一一对应。(注:ArkTS 中 async/await 是保留关键字,不能作为方法名,故语义层分别改名 asyncTask / awaitValue,语义不变。)
四、引擎层:桥 ArkTS 异步运行时
OhosCoroutinesEngine.ets 把"调度器"与"挂起"交给 ArkTS 原生设施:
typescript
export class OhosCoroutinesEngine {
mainScope(): CoroutineScope { return new CoroutineScope(); }
withContext<T>(_ctx, block): Promise<T> {
return Promise.resolve().then(() => Promise.resolve(block()));
}
delay(ms: number): Promise<void> {
return new Promise(resolve => setTimeout(resolve, ms));
}
}
要点:
withContext:按Dispatchers提示执行计算块(Main 直接续跑,Default/IO 经事件循环异步续跑),对齐"切换调度器"语义。delay:用setTimeout实现非阻塞延时,对齐kotlinx.coroutines.delay。- Default/IO 的真实后台化 :当前映射到事件循环异步调度(同属"非阻塞");若要把 CPU 密集任务真正放到后台线程,生产环境可进一步桥
@kit.ArkTS的taskpool(本系列 SQLDelight 已展示 RdbStore 异步派发思路)。
五、验收页:真机上验证
开发代码界面如下:

CoroutinesDemo.ets 三个按钮:
- 并发 launch 3 任务 :分别延时 300/100/200ms 启动三个
launch,日志会显示"B 先于 C 先于 A"完成------证明三个任务是并发而非顺序执行。 - async + await 计算 :
asyncTask计算 1...100000 求和,awaitValue拿到结果上屏,证明带返回值的异步任务可用。 - withContext 切换 :在
Dispatchers.Default下执行一段累加,await拿到返回值,证明调度器切换语义可用。
点一遍,日志区会按预期顺序滚动,状态从"运行中"切到"完成",证明协程 API 真实生效。
运行如下:




六、我的踩坑小结
- 不要"重写协程运行时":ArkTS 已是异步非阻塞模型,直接等价复刻 API 形状即可,硬造线程池反而违背平台模型。
async返回值要扁平化 :block()可能返回Promise<T>,用Promise.resolve(block())两层包一层,确保Deferred持有的是Promise<T>而非Promise<Promise<T>>。- 严格模式禁参数属性 :所有字段用普通参数 +
this.x = x。 catch不要无脑 rethrow :launch内任务失败若 rethrow 会产生未处理 rejection,演示里直接markDone吞掉即可。
总结
本文完整记录了 kotlinx.coroutines 在 OpenHarmony 上的真实适配路径。核心结论是:ArkTS 与 Kotlin 协程心智同构,无需重写运行时,只需语义等价复刻 。全文通过三层架构落地------语义层用 Promise 承载结构化并发原语,引擎层桥接 ArkTS 异步设施,验收页在真机上验证并发、异步与调度切换。最终以 4 条踩坑经验收尾,并开源全部源码,为 KMP 生态向鸿蒙迁移提供了一条可复用的实践范式。
社区引导
欢迎加入 KMP&CMP 鸿蒙社区:https://atomgit.com/CPF-KMP-CMP
本适配全部源码已开源在 AtomGit:https://atomgit.com/wdracky/kmp-ohos-adapters/tree/main/kotlinx-coroutines
如果你在适配过程中用到了 AI 辅助工具,推荐码道(AtomCode)专属通道
https://developer.huaweicloud.com/codeartsco.html?source=dmzntgwatomgit1\&sourcead=dmzntgwatomgiths