Kotlin Multiplatform for OpenHarmony 实战:为 Koin 实现依赖注入适配与 AbilityContext 桥接

发布时间:2026/10/19 2:10:03

Kotlin Multiplatform for OpenHarmony 实战:为 Koin 实现依赖注入适配与 AbilityContext 桥接 欢迎加入KMPCMP 鸿蒙社区 https://atomgit.com/CPF-KMP-CMP摘要本文演示如何将 Kotlin Multiplatform / Compose MultiplatformKMP CMP工程中常用的轻量级依赖注入框架 Koin适配到 OpenHarmony 平台。文章延续“语义层 / 引擎层 / 验收页”的三层适配思路语义层用纯 ArkTS 复刻 Koin 的 DI 契约Module、single/factory、KoinApplication、get()全程零kit.*引擎层把AbilityContext桥接进 DI 图作为平台能力的统一注入入口验收页通过get()注入一个从系统 Preferences 读取并加工数据的仓储把结果上屏验证 DI 平台桥接在真机上真实生效。适配后的代码已按 ArkTS 严格模式逐条核对可直接在 DevEco Studio 中编译运行。目录一、为什么挑 Koin 来做这次适配二、开发环境三、适配思路还是那套三层架构四、语义层复刻 Koin 的 DI 契约纯 ArkTS零 kit五、引擎层把 AbilityContext 桥接进 DI 图六、验收页注入一个仓储把系统数据上屏七、成果与经验总结八、适配产出与地址一、为什么挑 Koin 来做这次适配依赖注入DI是 Kotlin Multiplatform / Compose Multiplatform下文统称 KMP CMP工程里把“对象的创建”和“对象的使用”解耦的核心手段。Koin 作为一款轻量、纯 Kotlin 的 DI 框架凭借module { single { } }这种声明式 API 和极低的模板成本被大量跨平台项目采用。但当我们把同一套 KMP 工程搬到 OpenHarmony 时会撞上一个很现实的问题在 Android 侧Koin 模块里常见的androidContext()以及许多三方库依赖的Context在鸿蒙上根本不存在取而代之的是 ArkTS 的UIAbility与AbilityContext。换句话说“运行环境”这个被注入到图里的对象在鸿蒙上必须重新定义。本文以 Koin 的 DI 设计为蓝本在 OpenHarmony 侧用 ArkTS 等价复刻其 DI 契约并把AbilityContext作为平台能力的统一注入入口演示一个 KMP 依赖注入库在鸿蒙上的可落地适配方案。适配后的代码已按 ArkTS 严格模式逐条核对对照 SDK 的.d.ts可直接在 DevEco Studio 中编译运行。二、开发环境跨平台框架KMP v2.2.21 / CMP v1.9.2开发环境DevEco Studio 26.0.0 Release真机/模拟器ROM 6.1真实开发界面如下三、适配思路还是那套三层架构延续本系列“语义层 / 引擎层 / 验收页”的三层适配法把“写一套 DI 库”这件事拆成三层每一层职责单一、互不污染语义层Semantic用 ArkTS 复刻 Koin 的核心 DI 契约——Module、single/factory、KoinApplication、get()。这一层不碰任何kit.*纯粹描述“对象怎么注册、怎么取”可以跨端复用。引擎层Engine把 OpenHarmony 的平台能力桥接进 DI 图。重点是AbilityContext——我们用它拿到应用偏好存储ohos.data.preferences、包信息ohos.bundle.bundleManager从而让被注入的服务能够访问系统能力。验收页Verify一个 ArkTS 页面通过容器get()注入一个“从系统 Preferences 读取并加工数据”的仓储把结果上屏证明 DI 平台桥接在真机真实生效。四、语义层复刻 Koin 的 DI 契约纯 ArkTS零 kitKoin 的本质就是一个“按 key 存工厂、按 key 取实例、单例走缓存”的容器。我们用 ArkTS 把它等价复刻出来全程不引入任何鸿蒙系统 API// Koin.ets —— 语义层复刻 Koin 的 DI 契约 export interface Definition { readonly isSingleton: boolean; create(app: KoinApplication): Object; } export class Module { private readonly definitions: Mapstring, Definition new Mapstring, Definition(); single(key: string, factory: (app: KoinApplication) Object): void { this.definitions.set(key, { isSingleton: true, create: factory }); } factory(key: string, factory: (app: KoinApplication) Object): void { this.definitions.set(key, { isSingleton: false, create: factory }); } get raw(): Mapstring, Definition { return this.definitions; } } export class KoinApplication { private readonly module: Module; private readonly registry: Mapstring, Object new Mapstring, Object(); constructor(module: Module) { this.module module; } getT(key: string): T { const def: Definition | undefined this.module.raw.get(key); if (def undefined) { throw new Error(Koin: 未注册的定义 ${key}); } if (def.isSingleton) { const cached: Object | undefined this.registry.get(key); if (cached ! undefined) { return cached as T; } const created: Object def.create(this); this.registry.set(key, created); return created as T; } return def.create(this) as T; } } export function startKoin(module: Module): KoinApplication { return new KoinApplication(module); }这里有几个值得说的点第一Definition用具名接口而不是对象字面量联合类型这是为了躲开 ArkTS 严格模式的arkts-no-obj-literals-as-types第二容器在get时把this传进工厂使得single(greeting, app new GreetingRepository(app.get(platform)))这种“依赖反查”成为可能和国外 Koin 在模块内部直接get()是同构的第三单例缓存用Map手动管避免 ArkTS 对顶层可变状态的过度限制。五、引擎层把 AbilityContext 桥接进 DI 图Android 上的 Koin 靠androidContext()把Context塞进图里鸿蒙这边我们用AbilityContext扮演同样的角色。它来自kit.AbilityKit是 ArkTS 侧拿系统能力的入口// OhosKoinEngine.ets —— 引擎层AbilityContext 桥接 import { preferences } from kit.ArkData; import { bundleManager } from kit.AbilityKit; import { common } from kit.AbilityKit; export interface PlatformContext { readPref(key: string): Promisestring; writePref(key: string, value: string): Promisevoid; bundleName(): string; } export class OhosPlatformContext implements PlatformContext { private readonly ctx: common.UIAbilityContext; constructor(ctx: common.UIAbilityContext) { this.ctx ctx; } async readPref(key: string): Promisestring { const store: preferences.Preferences await preferences.getPreferences(this.ctx, koin_demo); return (await store.get(key, )) as string; } async writePref(key: string, value: string): Promisevoid { const store: preferences.Preferences await preferences.getPreferences(this.ctx, koin_demo); await store.put(key, value); await store.flush(); } bundleName(): string { const info: bundleManager.BundleInfo bundleManager.getBundleInfoForSelfSync( bundleManager.BundleFlag.GET_BUNDLE_INFO_DEFAULT ); return info.name; } }这一段就是本次适配的“真功夫”所在它把平台能力收敛成一个接口PlatformContext语义层完全不知道鸿蒙长什么样只认接口。到了鸿蒙侧AbilityContext 既提供了preferences偏好存储又提供了bundleManager包信息——被注入的仓储因此能读写系统持久化、能感知自身包名。六、验收页注入一个仓储把系统数据上屏最后用一个 ArkTS 页面把整条链路跑起来。它先在aboutToAppear里拿到AbilityContext搭出 DI 图再通过get()注入GreetingRepository调用其load()把“从 Preferences 读出并加工后的问候语”显示出来点“保存”写入后再重新注入取值形成闭环// KoinDemo.ets —— 验收页 import { router } from kit.ArkUI; import { common } from kit.AbilityKit; import { KoinApplication, Module, startKoin } from ./Koin; import { OhosPlatformContext, PlatformContext } from ./OhosKoinEngine; class GreetingRepository { private readonly platform: PlatformContext; constructor(platform: PlatformContext) { this.platform platform; } async load(): Promisestring { const saved: string await this.platform.readPref(name); const name: string saved.length 0 ? saved : OpenHarmony; return Hello, ${name}! (bundle: ${this.platform.bundleName()}); } async save(name: string): Promisevoid { await this.platform.writePref(name, name); } } function buildGraph(ctx: common.UIAbilityContext): KoinApplication { const m: Module new Module(); m.single(platform, () new OhosPlatformContext(ctx)); m.single(greeting, (app: KoinApplication) new GreetingRepository(app.getPlatformContext(platform))); return startKoin(m); } Entry Component struct KoinDemo { State message: string 加载中…; State input: string OpenHarmony; private koin?: KoinApplication; aboutToAppear(): void { const ctx: common.UIAbilityContext getContext(this) as common.UIAbilityContext; this.koin buildGraph(ctx); this.koin.getGreetingRepository(greeting).load().then((v: string) { this.message v; }); } build() { Column({ space: 16 }) { Text(Koin on OpenHarmony).fontSize(20).fontWeight(FontWeight.Bold) Text(KMP 三方库鸿蒙化适配 Demo · 依赖注入DI AbilityContext 桥接) .fontSize(12).fontColor(#666666) Text(this.message).fontSize(16).fontColor(#182431) .padding(12).backgroundColor(#F1F3F5).borderRadius(12).width(90%) // 省略 TextInput / 保存按钮 / 返回按钮完整代码见仓库 }.width(100%).padding(16).alignItems(HorizontalAlign.Center) } }页面打开后能立刻看到Hello, OpenHarmony! (bundle: 你的包名)说明greeting这个单例确实被注入、并且它的platform依赖AbilityContext桥也成功解析。点“保存并重新注入”写入的名字会从系统 Preferences 读回并刷新——这就是 DI 平台桥接在真机上跑通的铁证运行截图请见文末提交要求。七、成果与经验总结编译如下运行效果如下构造器不能带可见性修饰符ArkTS 严格模式禁止constructor(private readonly x)必须用普通参数 显式字段赋值。联合类型要具名内联对象字面量当类型会触发arkts-no-obj-literals-as-types像Definition这样拆成具名接口最稳。AbilityContext 不能在模块顶层取必须等组件就绪后用getContext(this)拿再传入buildGraph。Preferences 是异步的桥接出来的方法返回Promise验收页用.then或async处理避免同步取值拿到空。八、适配产出与地址适配仓库AtomGithttps://atomgit.com/oh-tpc/Koin适配方法已合入本系列“三层架构”模板语义层零kit.*引擎层桥kit.ArkDatakit.AbilityKit。欢迎加入KMPCMP 鸿蒙社区 https://atomgit.com/CPF-KMP-CMP如果你在适配过程中用到了 AI 辅助工具推荐码道AtomCode专属通道https://developer.huaweicloud.com/codeartsco.html?sourcedmzntgwatomgit1sourceaddmzntgwatomgiths
延伸阅读

更多相关文章

2026/10/19 2:10:03

数据结构——单向链表

具有线性关系的数据可以选择链式存储,链式存储每个环上要有自己的数据和下一个数据的地址1.单向链表的创建思路:创建一个头节点,代表这个链表开始的地方,不关心头节点的数据,头节点指向NULL,同时要返回头节…

2026/10/19 2:10:03

P1273 有线电视网 【洛谷算法习题】

P1273 有线电视网 网页链接 添加链接描述 题目描述 某收费有线电视网计划转播一场重要的足球比赛。他们的转播网和用户终端构成一棵树状结构,这棵树的根结点位于足球比赛的现场,树叶为各个用户终端,其他中转站为该树的内部节点。 从转播…

2026/10/19 2:10:03

加减【牛客tracker 每日一题】

加减时间限制:1 秒 空间限制:256M题目描述 小红拿到了一个长度为 nnn 的数组。她每次操作可以让某个数加 111 或者某个数减 111。 小红最多能进行 kkk 次操作。她希望操作结束后,该数组出现次数最多的元素次数尽可能多。 你能求出这个最大的次…

2026/10/19 3:25:06

Open-Code-Review:基于CLI+Git Diff+LLM的开放代码审查范式

1. “open-code-review”不是工具名,而是开源协作范式的重新定义很多人第一次看到“open-code-review”这个词,第一反应是——这是某个新出的 CLI 工具?是不是类似codex cli或claude code cli那种带大模型能力的代码审查命令行?我…

2026/10/19 3:25:06

open-code-review:一种基于Git Diff与LLM Agent的开放代码评审范式

1. “open-code-review”不是工具名,而是正在发生的开发范式迁移你最近在 GitHub 提交 PR 后,是不是发现评论区里多了一条带 🤖 图标的自动反馈?它没写“LGTM”,也没说“请加单元测试”,而是直接指出&#…

2026/10/19 3:25:06

open-code-review:基于git diff与本地LLM的轻量级代码评审范式

1. “open-code-review”不是工具名,而是一套可落地的代码评审新范式“open-code-review”这个词最近在开发者社区里频繁出现,但它既不是某个开源项目仓库的官方名称,也不是某家大厂刚发布的SaaS产品。我第一次在内部技术分享会上听到它&…

2026/10/19 3:25:06

open-code-review:基于Git Diff与CLI的AI代码审查范式

1. 项目概述:这不是又一个代码审查工具,而是一次开发工作流的底层重定义“open-code-review”这个名称乍看平平无奇,像极了某个开源社区里默默无闻的 GitHub 仓库名——但如果你最近在终端里敲过codex cli、在飞书机器人里配置过 LLM 接入、或…

2026/10/19 3:25:06

MATLAB项目迁移Python全流程复盘:规划、重构与AI辅助避坑

自己踩过不少坑,也帮别人擦过不少屁股,所以这篇东西我不想写成一板一眼的教程,更想把它当成一次"过来人复盘"。我会从迁徙项目的规划和拆解入手,再到实操落地、常见坑点,尽量把那些文档里不写、但实战中特别…

2026/10/19 3:20:06

五种经典排序算法详解:从原理到工程实践

排序算法这东西,科班出身的人大学里多少都学过,工作几年的老码农也不见得能徒手把每种细节都写对。前阵子我帮团队做一次代码评审,发现一个功能里明明只需要取前K个最大元素,结果有人直接写了个冒泡排序去排整个数组,数…

2026/10/18 0:01:50

金融AI落地指南:从调研报告到技术选型与工程实践

简介:这份PDF报告聚焦2025年金融服务业中国AI现状与趋势,面向金融科技从业者、AI战略规划人员及关注行业数字化转型的研究者,帮助读者把握生成式AI在银行、支付、交易等场景中的落地路径与投资方向。资源包内含1个PDF文件,大小约1…

2026/10/19 0:04:56

悟空开源无代码平台实战:从实体建模到应用设计避坑指南

简介:基于悟空开源无代码平台的多种应用设计源码,面向希望在不编写代码的情况下快速搭建CRM、HRM、财务系统、ERP、SRM等业务应用的企业与技术人员,通过拖放式界面和内置模板即可完成应用定制与部署。压缩包共697个文件,约10.74MB…

2026/10/19 0:04:56

基于.NET9的多租户权限系统:数据权限与动态API落地实践

简介:这份资源是一套面向 .NET 与 Vue 全栈开发者的中台权限管理系统,后端基于 .Net9,前端采用 Vue3 Element Plus,并配套 uniapp uviewui 移动端方案,实现前后端分离。系统覆盖多租户隔离、数据权限、动态 Api、任务…

2026/10/19 0:04:56

场地预约小程序毕设实战:SSM+微信小程序+MySQL数据库设计到避坑

简介:面向毕业设计场景的场地预约小程序完整项目,基于微信小程序SSMMySql技术栈开发,适合计算机相关专业学生作为选题参考、功能扩展或二次开发起点。系统实现场地类型管理、场地管理、预约管理、取消申请与押金退回等功能,分为管…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑