开源鸿蒙平台 KMP_CMP 三方库「意图路由」适配全流程
本文记录
kmp-intent-router接入开源鸿蒙(OpenHarmony)Want、深链和分享入口能力的完整过程,覆盖 KMP/CMP 工程盘点、ohosArm64目标、Kotlin/Native 动态库、C ABI/N-API 桥接、ArkUI 真机页面、Want 参数路由、签名 HAP 和真机验收。本次适配复用 Kotlin 侧的意图模型、过滤器匹配、URI 解析、优先级路由、JSON 契约和自检逻辑,再由 ArkTS 调用 HarmonyOS
@ohos.app.ability.Want与 Ability 生命周期完成意图分发。验证的是同一份 KMP 代码在 OpenHarmony ARM64 设备上的运行结果,而不是重新写一套只在页面里生效的路由数据。
项目地址: AtomGit/oh-tpc/kmp-intent-router
开发工具: 华为云码道
一、背景
1.1 为什么做开源鸿蒙平台 KMP/CMP 适配
意图路由是 HarmonyOS/OpenHarmony 应用框架的基础能力。应用通过 Want 描述动作、URI、分类和参数,系统根据 module.json5 中声明的 skills 过滤器把请求交给对应 Ability;深链和分享入口本质上是同一个匹配问题的不同来源。
如果只把页面重新写成 ArkTS,页面可能显示几条路由卡片,却无法证明公共 Kotlin 模型、Native 动态库、N-API 和匹配引擎已经连通。适配需要解决 KMP 目标、工具链、跨语言对象、Want 路由、URI 参数捕获和签名交付等边界。
| 障碍 | 具体问题 |
|---|---|
| 目标缺失 | KMP 默认只有 JVM,必须增加 ohosArm64() 才能生成 ARM64 Native 动态库。 |
| 匹配规则边界 | 路径模板、通配符、查询参数解码和优先级排序必须只实现一次,不允许 ArkTS 复制一份。 |
| 语言边界不同 | ArkTS 不能直接持有 Kotlin data class,必须经过 C ABI、C++ N-API 和 JSON。 |
| Want 配置边界 | API 20 Stage 使用 skills 声明 action、scheme、host,运行时参数通过 Want.uri 回传。 |
| 确定性要求 | 同一意图在任何平台上必须得到同一条匹配结果,排序规则不能有平台差异。 |
1.2 库提供的能力
intent-router 公共模块提供 Intent、IntentFilter、IntentRoute、IntentRouter、目录、八项自检和无依赖 JSON 序列化。
| ID | 标题 | 说明 | 路径模板 |
|---|---|---|---|
daily-focus | 每日专注 | 打开今日专注任务 | /focus/{taskId} |
package-delivery | 配送进度 | 查看配送订单 | /delivery/* |
device-status | 设备概览 | 查看设备状态 | /device |
1.3 实现适配
| 维度 | 要求 |
|---|---|
| 代码复用 | 意图模型、过滤器、URI 解析、优先级排序、JSON 和自检由 Kotlin 共享。 |
| 平台目标 | 公共模块和示例加入 ohosArm64,生成 libintent_router.so。 |
| 桥接稳定 | 使用少量 C ABI 函数和 JSON,避免跨语言对象地址。 |
| UI 完整 | 页面支持路由切换、URI 输入、解析结果、参数捕获和自检展示。 |
| 仓库规范 | 项目说明、文章、效果图和源码链接统一使用 AtomGit。 |
二、实现路线图
第 1 阶段:项目初始化 ── 盘点 KMP 模块、意图模型和 OpenHarmony 边界
第 2 阶段:目标与依赖打通 ── 加入 ohosArm64、独立 example 和 Native 任务
第 3 阶段:模型与序列化 ── 建立 Intent、Filter、Route、自检和 JSON 契约
第 4 阶段:原生桥接 ── Kotlin/Native C ABI、C++ N-API 和内存释放
第 5 阶段:系统能力封装 ── Want 路由、skills 声明和深链参数回传
第 6 阶段:示例与验证 ── ArkUI 页面、签名 HAP、设备安装和效果图
三、逐步实现过程
第 1 阶段:项目初始化
1.1 盘点
公共 API 和工程边界:
intent-router/ KMP 意图模型、匹配器、自检和 JSON 边界
vico/ 参考工程一致的库聚合层
sample/ android/desktop/shared/web/ios 主机入口
example/shared/ 示例门面和 JVM 验收测试
example/nativeApp/ ohosArm64 Kotlin/Native 动态库
example/ohosApp/ DevEco Stage 工程和 ArkUI 页面
scripts/ Native、HAP 和签名工程辅助脚本
docs/openharmony/ 验收记录和真机效果图
guide/ 集成指南
1.2 固定工具链和版本矩阵
| 项目 | 配置 | 用途 |
|---|---|---|
| Kotlin Multiplatform | 2.2.21-1.0.0 | JVM、Kotlin/Native 和 KLIB |
| JDK | 21 | Gradle、Kotlin 编译和 Native 任务 |
| OpenHarmony 目标 | ohosArm64 | ARM64 真机动态库 |
| DevEco product | 6.0.0(20) | 工程兼容和目标版本 |
| ABI | arm64-v8a | HAP 原生库架构 |
1.3 页面边界
页面围绕"当前路由、过滤器、URI 输入和解析结果"组织:英雄头部与自检徽章、横滑路由选择区、详情区(ROUTE/ACTION/FILTER/PATH 和优先级徽章)、测试入口区和结果展示区。路由切换只读取 KMP/N-API 目录,解析按钮才构造 Intent 并调用匹配引擎。
第 2 阶段:目标与依赖打通
2.1 加入 ohosArm64 目标
kotlin {
explicitApi()
jvm()
jvmToolchain(21)
ohosArm64()
}
2.2 Native focused build
Native 任务生成 libintent_router.so 和 libintent_router_api.h,复制到 entry/libs/arm64-v8a 和 C++ include 目录。Stage HAP 使用纯 ArkTS 路由适配器(IntentRouterClient.ets),Native 桥保留在 example/nativeApp 做独立 KMP/Native 验证。
第 3 阶段:模型与序列化
3.1 JSON 契约
KMP IntentRouterEngine -> Kotlin/Native C ABI -> C++ N-API
-> IntentRouterClient.ets -> Index.ets -> resolve/parameters
3.2 公共模型
public data class Intent(
val action: String?,
val uri: String?,
val categories: Set<String> = emptySet(),
val extras: Map<String, String> = emptyMap(),
)
public data class IntentFilter(
val action: String? = null,
val scheme: String? = null,
val host: String? = null,
val pathPattern: String? = null,
val categories: Set<String> = emptySet(),
val requiredExtras: Map<String, String> = emptyMap(),
)
IntentRouter 注册表拒绝冲突路由;八项自检覆盖路由数量、ID 唯一性、action/path 声明、优先级非负、模板深链解析、路径参数捕获、分发结果和非法 action 拒绝。
第 4 阶段:原生桥接(技术难点)
4.1 三层桥接
ArkTS JSON string -> C++ N-API entry -> Kotlin/Native C ABI
-> IntentRouterEngine + UTF-8 JSON + explicit free
C++ 只负责参数检查、UTF-8 字符串转换和 Native 释放,不复制 Kotlin 匹配规则。
4.2 CMake 边界
add_library(intent_router SHARED IMPORTED)
add_library(entry SHARED napi_init.cpp)
target_include_directories(entry PRIVATE "include")
target_link_libraries(entry PRIVATE intent_router libace_napi.z.so)
第 5 阶段:系统能力封装
5.1 Want 与 skills 声明
module.json5 的 skills 声明 entity.system.home、ohos.want.action.home,深链由过滤器字段在运行时比对,不在 profile 中重复维护。
5.2 Ability 参数回传
private applyWant(want: Want): void {
const index = want.parameters?.['requestedRouteIndex'];
AppStorage.setOrCreate('requestedRouteIndex', typeof index === 'number' ? index : 0);
}
onCreate(want: Want, _launchParam: AbilityConstant.LaunchParam): void {
this.applyWant(want);
}
onNewWant(want: Want, _launchParam: AbilityConstant.LaunchParam): void {
this.applyWant(want);
}
页面通过 @StorageProp 监听该字段,Want 到达后自动切换到对应路由。
第 6 阶段:示例与验证
export JAVA_HOME="/path/to/jdk-21"
./scripts/build-openharmony.sh
python3 scripts/prepare-signing-project.py /tmp/kmp-router-sign
bash scripts/build-hap.sh /tmp/kmp-router-sign
hdc install -r entry-default-signed.hap
hdc shell aa start -a EntryAbility -b com.ohos.kmp.intentrouter
签名证书、profile、p12 和密码只保存在本机,不要提交到 AtomGit。
四、完整代码对照
4.1 整体架构
KMP IntentRouterEngine -> Kotlin/Native -> libintent_router.so
-> C++ N-API -> IntentRouterClient.ets -> Index.ets
-> Want / deep link / share -> EntryAbility.onCreate / onNewWant
-> resolve -> routeId + parameters -> host navigation
4.2 文件清单
| 文件 | 职责 |
|---|---|
intent-router/Intent.kt | 意图、过滤器、路由和匹配结果模型 |
intent-router/IntentRouter.kt | 注册表、匹配引擎、优先级排序和自检 |
intent-router/IntentJson.kt | JSON 编码和转义 |
example/nativeApp/NativeBridge.kt | C ABI、JSON 返回和内存释放 |
entry/src/main/cpp/napi_init.cpp | N-API 导出和参数检查 |
entry/src/main/ets/intentrouter/IntentRouterClient.ets | 目录读取和意图解析适配 |
entry/src/main/ets/intentrouter/IntentRouterFormManager.ets | Form Kit 卡片数据绑定 |
entry/src/main/ets/entryability/EntryAbility.ets | Want 参数路由 |
entry/src/main/ets/pages/Index.ets | 真机示例页面 |
4.3 关键 API 对照
| 层次 | API | 作用 |
|---|---|---|
| Kotlin | IntentRouterEngine.catalog | 生成路由目录 |
| Kotlin | IntentRouter.resolve/resolveAll | 确定性意图匹配 |
| Kotlin | IntentRouterEngine.runChecks | 八项公共自检 |
| Native | IntentRouterGet | 返回 JSON 路由 |
| N-API | getRoute / resolve | 向 ArkTS 暴露目录和解析 |
| ArkTS | IntentRouterClient.resolve | 构造请求并返回匹配 |
| Ability | onCreate / onNewWant | 接收 Want 参数 |
五、关键决策说明
决策 1:ohosArm64 是适配验收的一部分
只有真正链接 ARM64 动态库,才能证明共享 Kotlin 代码进入 OpenHarmony 运行时。
决策 2:JSON 作为跨语言数据契约
JSON 让 ArkTS、C++ 和 Kotlin/Native 的边界清楚可调试,并避免暴露内部对象布局。
决策 3:匹配规则只实现一次
路径模板、通配符、URI 解码和优先级排序只存在于 Kotlin 公共模块;ArkTS 适配器只做目录读取和请求转发,不复制任何匹配逻辑,保证各平台结果一致。
决策 4:路由 ID 贯穿全部界面
页面选中状态、Want 参数、Form Kit 卡片和匹配结果使用同一个 routeId,避免深链到达后页面显示与路由不符。
决策 5:库验证和设备验证分开
JVM 验证匹配规则,Native 验证 ABI,Hvigor 验证 HAP,真机验证自检、解析和 Want 路由。
六、测试与验证
6.1 测试环境
本次真机验证使用 macOS、Kotlin Multiplatform 2.2.21-1.0.0、DevEco Studio API 20 ARM64 SDK、签名 HAP、USB HarmonyOS ARM64 真机和 hdc 序列号 FMR0223825079397。
6.2 静态检查与单元测试
./gradlew :intent-router:jvmTest :sample:shared:jvmTest :example:shared:jvmTest
(cd example && ./gradlew :shared:jvmTest :nativeApp:prepareOhos)
6.3 功能验证用例
用例 1:默认页面和自检
启动应用后显示"意图路由"英雄区和 8/8 自检通过 徽章,目录由 KMP/N-API 读取。
用例 2:三条路由切换
点击"每日专注"“配送进度”“设备概览”,标题、说明、ROUTE/ACTION/FILTER/PATH 和优先级徽章同步更新,不依赖任何系统服务。
用例 3:意图解析和参数捕获
输入 cmp://intent.example/focus/today?source=widget 并点击"解析当前意图",页面返回 daily-focus,参数区逐条显示 source = widget 与 taskId = today。
用例 4:未匹配意图
输入不匹配的 URI 时,结果卡片显示"未找到匹配路由"的错误样式而不是假装成功。
6.4 验证结论
公共模型、ArkTS 适配器、Hvigor HAP 构建、签名安装、路由切换、意图解析和参数捕获均已验证。解析结果与 KMP 目录一致,说明从页面输入到公共匹配引擎的链路已连通。
七、运行效果
7.1 真机截图

截图中可以看到英雄区的自检徽章、三条路由的横滑选择卡片(每日专注 / 配送进度 / 设备概览)、带 PRIORITY 徽章的详情面板(ROUTE、ACTION、FILTER、PATH 和能力标签),以及测试入口区的 URI 输入、解析按钮和绿色结果卡片。路由名称与 KMP 目录和页面按钮一致。
7.2 应用内页面效果
应用页面采用深色分层布局:英雄区使用渐变背景承载标题和自检状态,路由选择区为横滑卡片并按路由着色,详情区为非对称面板(图标 + 标题 + 优先级徽章),测试入口区按当前路由主题色高亮解析按钮,解析结果以绿/红卡片区分成功与未匹配。
八、遗留问题与改进方向
8.1 踩坑复盘
- 只改 ArkTS 页面不算 KMP 适配:必须把共享匹配引擎编译成
ohosArm64动态库。 - N-API 不负责业务判断:C++ 只做类型检查、字符串转换和释放。
- 匹配规则不能双份维护:ArkTS 侧出现第二份匹配实现是确定性破坏的第一步。
- URI 解析必须覆盖边界:空 host、端口、
#fragment 和%编码在公共模块统一处理。 - 路由 ID 必须稳定:
routeId是页面选择、Want 参数和匹配结果的唯一关联字段。
8.2 已知问题
- JVM 单元测试需要 JDK 21,本机仅装 JDK 25 时 Kotlin 会拒绝解析版本号;
- Want 深链到达后的路由预选依赖宿主应用传入
requestedRouteIndex; - 签名配置只适用于本地开发机,不能直接复制到其他环境;
- 多模块应用需要为每个目标 module 维护对应的 skills 声明。
8.3 未来优化方向
- 增加跨平台
expect/actualWant 构造接口; - 用生成配置减少 KMP 路由声明与 ArkTS skills 的重复维护;
- 增加过滤器冲突检测和注册期诊断;
- 为 Compose Multiplatform 提供统一的路由解析组件;
- 在持续集成中加入 Native 链接、HAP 构建和自检结构检查。
九、总结
9.1 核心难点回顾
KMP IntentRouterEngine -> Kotlin/Native ARM64 -> C ABI -> C++ N-API
-> ArkTS JSON 校验 -> IntentRouterClient -> resolve
-> Want / deep link -> EntryAbility routeId 路由
9.2 封装层次
- KMP 层:定义意图、过滤器、路由、匹配、排序和 JSON;
- Native 层:生成 ARM64 动态库并输出有限 C ABI;
- N-API 层:完成参数检查、字符串转换和内存释放;
- ArkTS 层:管理页面、目录读取、意图解析、Want 路由和 Ability 生命周期;
- DevEco 层:完成 CMake、HAP、签名、安装和运行。
9.3 三条经验
- 先让匹配引擎在 JVM 和 Native 通过,再接入 ArkUI 和系统服务;
- 用 JSON 和少量 C ABI 代替跨语言对象传递;
- 把 Want 声明、运行时解析和页面预选分别记录,避免把"页面能切"误认为"深链已经路由"。
9.4 适配成果
当前 kmp-intent-router 已完成公共意图模型、八项自检、Kotlin/Native + C ABI + N-API 桥接、Want 参数路由、EntryAbility.onCreate/onNewWant 回传、ArkUI 真机示例页面、签名 HAP 构建、设备安装和真机效果图。项目目录、文档、图片和源码地址统一使用 AtomGit。
参考文档
更多推荐




所有评论(0)