本文记录 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 公共模块提供 IntentIntentFilterIntentRouteIntentRouter、目录、八项自检和无依赖 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 Multiplatform2.2.21-1.0.0JVM、Kotlin/Native 和 KLIB
JDK21Gradle、Kotlin 编译和 Native 任务
OpenHarmony 目标ohosArm64ARM64 真机动态库
DevEco product6.0.0(20)工程兼容和目标版本
ABIarm64-v8aHAP 原生库架构
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.solibintent_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.json5skills 声明 entity.system.homeohos.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.ktJSON 编码和转义
example/nativeApp/NativeBridge.ktC ABI、JSON 返回和内存释放
entry/src/main/cpp/napi_init.cppN-API 导出和参数检查
entry/src/main/ets/intentrouter/IntentRouterClient.ets目录读取和意图解析适配
entry/src/main/ets/intentrouter/IntentRouterFormManager.etsForm Kit 卡片数据绑定
entry/src/main/ets/entryability/EntryAbility.etsWant 参数路由
entry/src/main/ets/pages/Index.ets真机示例页面

4.3 关键 API 对照

层次API作用
KotlinIntentRouterEngine.catalog生成路由目录
KotlinIntentRouter.resolve/resolveAll确定性意图匹配
KotlinIntentRouterEngine.runChecks八项公共自检
NativeIntentRouterGet返回 JSON 路由
N-APIgetRoute / resolve向 ArkTS 暴露目录和解析
ArkTSIntentRouterClient.resolve构造请求并返回匹配
AbilityonCreate / 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 = widgettaskId = today

用例 4:未匹配意图

输入不匹配的 URI 时,结果卡片显示"未找到匹配路由"的错误样式而不是假装成功。

6.4 验证结论

公共模型、ArkTS 适配器、Hvigor HAP 构建、签名安装、路由切换、意图解析和参数捕获均已验证。解析结果与 KMP 目录一致,说明从页面输入到公共匹配引擎的链路已连通。

七、运行效果

7.1 真机截图

在这里插入图片描述

截图中可以看到英雄区的自检徽章、三条路由的横滑选择卡片(每日专注 / 配送进度 / 设备概览)、带 PRIORITY 徽章的详情面板(ROUTE、ACTION、FILTER、PATH 和能力标签),以及测试入口区的 URI 输入、解析按钮和绿色结果卡片。路由名称与 KMP 目录和页面按钮一致。

7.2 应用内页面效果

应用页面采用深色分层布局:英雄区使用渐变背景承载标题和自检状态,路由选择区为横滑卡片并按路由着色,详情区为非对称面板(图标 + 标题 + 优先级徽章),测试入口区按当前路由主题色高亮解析按钮,解析结果以绿/红卡片区分成功与未匹配。

八、遗留问题与改进方向

8.1 踩坑复盘

  1. 只改 ArkTS 页面不算 KMP 适配:必须把共享匹配引擎编译成 ohosArm64 动态库。
  2. N-API 不负责业务判断:C++ 只做类型检查、字符串转换和释放。
  3. 匹配规则不能双份维护:ArkTS 侧出现第二份匹配实现是确定性破坏的第一步。
  4. URI 解析必须覆盖边界:空 host、端口、# fragment 和 % 编码在公共模块统一处理。
  5. 路由 ID 必须稳定routeId 是页面选择、Want 参数和匹配结果的唯一关联字段。

8.2 已知问题

  • JVM 单元测试需要 JDK 21,本机仅装 JDK 25 时 Kotlin 会拒绝解析版本号;
  • Want 深链到达后的路由预选依赖宿主应用传入 requestedRouteIndex
  • 签名配置只适用于本地开发机,不能直接复制到其他环境;
  • 多模块应用需要为每个目标 module 维护对应的 skills 声明。

8.3 未来优化方向

  • 增加跨平台 expect/actual Want 构造接口;
  • 用生成配置减少 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 三条经验

  1. 先让匹配引擎在 JVM 和 Native 通过,再接入 ArkUI 和系统服务;
  2. 用 JSON 和少量 C ABI 代替跨语言对象传递;
  3. 把 Want 声明、运行时解析和页面预选分别记录,避免把"页面能切"误认为"深链已经路由"。

9.4 适配成果

当前 kmp-intent-router 已完成公共意图模型、八项自检、Kotlin/Native + C ABI + N-API 桥接、Want 参数路由、EntryAbility.onCreate/onNewWant 回传、ArkUI 真机示例页面、签名 HAP 构建、设备安装和真机效果图。项目目录、文档、图片和源码地址统一使用 AtomGit。

参考文档

Logo

一站式 AI 云服务平台

更多推荐