开源鸿蒙平台 KMP_CMP 三方库「kotlinx.immutable」适配全流程
本文记录
kotlinx.collections.immutable适配 OpenHarmony 的完整过程,覆盖 KMP/CMP 工程盘点、ohosArm64目标、持久化集合能力、Kotlin/Native 动态库、C ABI/N-API 桥接、ArkUI 功能总览页面、未签名 HAP、调试签名和真机运行。本次适配复用库原有的
commonMain集合接口和实现,只新增 OpenHarmony ARM64 编译目标及验证宿主。ArkTS 页面通过 N-API 调用 Kotlin/Native 生成的真实集合结果,不在页面中重新实现一套集合逻辑。
项目地址: AtomGit/oh-tpc/kotlinx.collections.immutable
上游仓库: Kotlin/kotlinx.collections.immutable
开发工具: 华为云码道
环境安装: 环境安装指南
一、背景
1.1 为什么做 OpenHarmony 平台 KMP/CMP 适配
kotlinx.collections.immutable 是 Kotlin 官方生态中的多平台集合库,提供不可变集合接口和持久化集合实现。标准库的 List、Set、Map 主要表达“调用方不能通过当前引用修改”,但不保证底层对象没有其他可变引用;本库通过持久化数据结构让集合快照可以安全共享。
原工程已经覆盖 JVM、JS、Wasm 和 Kotlin/Native 多个平台,但没有 OpenHarmony ohosArm64 目标。只修改 ArkTS 页面或只把标准集合转换成 JSON,都不能证明这份 KMP 集合实现真正运行在鸿蒙设备上。因此适配需要解决以下问题:
| 障碍 | 具体问题 |
|---|---|
| 目标缺失 | 核心 KMP 模块没有 ohosArm64(),无法生成 OpenHarmony KLIB。 |
| 工具链不一致 | Kotlin/Native、Gradle、OpenHarmony LLVM、JDK 和 Native SDK 必须匹配。 |
| 跨语言边界 | ArkTS 不能直接持有 Kotlin PersistentList、PersistentSet 或 PersistentMap,必须通过 C ABI、C++ N-API 和 JSON。 |
| 数据语义容易被误解 | 示例需要同时展示 immutable 接口、persistent 实现、hash 工厂、转换函数和批量修改。 |
| 生命周期管理 | Native 返回的 C 字符串必须由明确的 Free 函数释放,避免页面重复读取造成内存泄漏。 |
| 交付链路复杂 | 动态库、CMake、HAP、签名、设备安装和 ARM64 依赖需要分别验收。 |
因此,本项目把适配边界放在三个地方:KMP 目标配置、Kotlin/Native C ABI/N-API 桥接层和 ArkUI 展示层。集合的创建、更新、结构共享和检查仍由 Kotlin 代码完成,ArkTS 只负责调用和展示。
1.2 库提供的能力
本库不是一个只提供 listOf 的工具类,而是一套完整的不可变和持久化集合 API:
| 能力 | 主要 API | 说明 |
|---|---|---|
| 不可变接口 | ImmutableCollection、ImmutableList、ImmutableSet、ImmutableMap | 提供稳定、只读的集合契约。 |
| 持久化接口 | PersistentCollection、PersistentList、PersistentSet、PersistentMap | 修改操作返回新集合,旧集合保持不变。 |
| 有序工厂 | persistentListOf、persistentSetOf、persistentMapOf | 默认保留集合元素的插入迭代顺序。 |
| 哈希工厂 | persistentHashSetOf、persistentHashMapOf | 更注重时间和空间效率,不保证迭代顺序。 |
| immutable 工厂 | immutableListOf、immutableSetOf、immutableMapOf | 提供语义明确的不可变集合入口。 |
| 转换函数 | toImmutable*、toPersistent*、toPersistentHash* | 把标准集合、数组、序列转换成库类型。 |
| 快照更新 | adding、removing、putting、replacingAt | 返回新快照,尽量复用旧集合结构。 |
| 批量修改 | builder、build、mutate | 在临时可变构建器中集中修改,再生成一个持久化结果。 |
| 适配器 | ImmutableListAdapter、ImmutableSetAdapter、ImmutableMapAdapter | 把已有只读集合包装成 immutable 接口。 |
1.3 实现适配
| 维度 | 要求 |
|---|---|
| 代码复用 | 集合接口、Trie/Vector/Map 实现、转换函数和自检逻辑全部来自 commonMain。 |
| 平台目标 | 为核心模块增加 ohosArm64,生成 OpenHarmony KLIB 并链接 libimmutablecollections.so。 |
| 桥接稳定 | 只导出目录、索引读取、随机读取、自检和释放四类 C ABI 函数。 |
| UI 完整 | 页面一次性列出 12 类主要功能,并显示 Kotlin 真实计算得到的结果。 |
| 可测试 | JVM 测试、Native 编译、动态库链接、HAP 构建和设备启动分别验收。 |
| 签名安全 | 源码只保留签名入口,证书、profile 和密钥材料由开发者本机配置。 |
| 仓库规范 | 项目文档、文章、效果图和源码链接统一使用 AtomGit。 |
示例页面是独立的真机验收宿主。业务项目仍然可以只依赖
kotlinx.collections.immutable,按照自身 Compose/CMP 或 ArkUI 状态管理方式使用集合。
二、实现路线图
第 1 阶段:项目初始化 ── 盘点集合 API、KMP 模块和 OpenHarmony 示例边界
第 2 阶段:目标与依赖打通 ── 加入 ohosArm64、独立 example 工程和 Native 构建任务
第 3 阶段:功能总览模型 ── 用 Kotlin 构造 12 类真实集合能力和统一 JSON 结构
第 4 阶段:原生桥接 ── Kotlin/Native C ABI、C++ N-API、参数检查和内存释放
第 5 阶段:ArkUI 页面 ── 展示 immutable/persistent API、转换、Builder 和 mutate
第 6 阶段:构建与验证 ── JVM 测试、Native 链接、未签名 HAP、调试签名和设备运行
每个阶段都使用真实产物作为下一阶段输入:先验证共享 Kotlin 逻辑,再把同一份代码链接为 ARM64 动态库,随后由 CMake 和 N-API 加载到 Stage 工程,最后在鸿蒙设备上启动页面。
三、逐步实现过程
第 1 阶段:项目初始化
1.1 盘点公共 API 和工程边界
项目采用独立核心库、Native 宿主和 DevEco 工程三层结构:
kotlinx.collections.immutable/
├── core/ KMP 核心库
│ ├── commonMain/src/ immutable/persistent API 和实现
│ ├── commonTest/src/ 跨平台契约测试
│ └── build.gradle.kts KMP 目标和发布配置
├── example/
│ ├── shared/ JVM/OHOS 示例和功能检查
│ ├── nativeApp/ ohosArm64 动态库和 C ABI
│ └── ohosApp/ DevEco Stage、N-API 和 ArkUI 页面
├── scripts/ 构建、签名工程和 HAP 脚本
└── docs/openharmony/ 构建与设备验收记录
example 是独立 Gradle 工程,DevEco 工程不是根项目的 Kotlin 子模块。这样 Gradle 可以单独发布和链接 Native,Hvigor 可以单独执行资源、CMake、ArkTS 和 HAP 任务。
1.2 固定工具链和版本矩阵
| 项目 | 配置 | 用途 |
|---|---|---|
| Kotlin Multiplatform | 2.2.21-1.0.0 | 支持参考工程使用的 OpenHarmony Native 目标。 |
| JDK | 21 | Gradle、Kotlin 编译和 Native 任务。 |
| OpenHarmony 目标 | ohosArm64 | ARM64 真机 KLIB 和动态库。 |
| DevEco product | default | Stage HAP 构建。 |
| DevEco Studio | 5.1.0 Release | IDE 版本,负责工程同步、HAP 构建与签名 |
| ABI | arm64-v8a | HAP 原生库目录。 |
| C++ 桥接 | N-API | 将 C 字符串转换为 ArkTS 字符串。 |
执行脚本前可以显式选择 JDK 21:
export JAVA_HOME="/path/to/jdk-21"
java -version
在 macOS 上,仓库脚本在 JAVA_HOME 未设置时会自动尝试使用 Homebrew 的 /opt/homebrew/opt/openjdk@21。
1.3 创建功能总览页面
功能总览不是随意填充几条字符串,而是由 Kotlin 侧建立真实目录:
PersistentList persistentListOf + adding
PersistentSet persistentSetOf + 去重
PersistentMap persistentMapOf + putting
PersistentHashSet persistentHashSetOf
PersistentHashMap persistentHashMapOf
Immutable factories immutableListOf / immutableSetOf / immutableMapOf
Conversions toImmutable* / toPersistent*
+ and - operators 持久化加减运算
Builder builder() / build()
Batch mutate mutate { }
Immutable adapters 三类 Adapter
Type interfaces immutable/persistent 接口体系
ArkUI 页面直接渲染这个目录,因此用户打开 HAP 就能看到库的主要功能边界,而不是只看到一个随机列表。
第 2 阶段:目标与依赖打通
2.1 加入 ohosArm64 目标
核心模块在保留现有目标的同时加入:
kotlin {
applyDefaultHierarchyTemplate()
explicitApi()
linuxX64()
linuxArm64()
ohosArm64()
macosX64()
macosArm64()
iosArm64()
// 其他原有目标保持不变
}
ohosArm64 与 native 层级共享 commonMain 的集合实现,不增加一套鸿蒙专属 List、Set 或 Map。
2.2 Native focused build 的作用
example/nativeApp 构建一个受 linker map 约束的 shared library:
kotlin {
ohosArm64 {
binaries.sharedLib {
baseName = "immutablecollections"
linkerOpts("--entry=0")
linkerOpts("--version-script=${project.file("src/ohosArm64Main/linker/shared-library.map")}")
linkerOpts("-lace_napi.z", "-luv", "-lhilog_ndk.z")
}
}
}
导出的符号为:
ImmutableCollectionsCatalog
ImmutableCollectionsGet
ImmutableCollectionsRandom
ImmutableCollectionsRunChecks
ImmutableCollectionsFree
链接器只开放这些明确入口,Kotlin/Native 内部实现不会变成不受控的 ABI。
2.3 配置独立消费工程
example/shared 通过本地 Maven 消费适配后的库:
kotlin {
jvm()
ohosArm64()
sourceSets {
commonMain.dependencies {
api("org.jetbrains.kotlinx:kotlinx-collections-immutable:${property("immutableCollectionsVersion")}")
}
}
}
根工程先执行 publishToMavenLocal,示例工程再解析相同版本,确保示例不是偷偷依赖根项目源码。
2.4 通过构建产物消费共享库
prepareOhos 在 Native 链接成功后复制:
from(layout.buildDirectory.dir("bin/ohosArm64/debugShared")) {
include("libimmutablecollections.so")
into("libs/arm64-v8a")
}
from(layout.buildDirectory.dir("bin/ohosArm64/debugShared")) {
include("libimmutablecollections_api.h")
into("src/main/cpp/include")
}
动态库和头文件属于构建产物,源码仓库不提交 DevEco/CMake 中间目录;开发者执行脚本即可重新生成。
第 3 阶段:功能总览模型
3.1 为什么需要统一 JSON 契约
ArkTS、C++ 和 Kotlin/Native 不能直接共享 Kotlin 泛型集合对象,因此边界使用 UTF-8 JSON:
PersistentList/Set/Map 实例
↓ Kotlin catalog()
ImmutableCollectionsExample
↓ Kotlin/Native toJson()
C ABI char*
↓ C++ napi_create_string_utf8()
ArkTS JSON.parse()
↓
功能总览卡片
页面只消费 JSON,不复制集合创建和更新逻辑。JVM 测试与设备页面使用同一份 catalog 和 runChecks。
3.2 示例数据结构
public data class ImmutableCollectionsExample(
val id: String,
val kind: String,
val value: String,
val size: Int,
)
kind 表示功能类别,value 保存可读的 API 示例和运行结果,size 用于页面右侧的数量提示。
3.3 真实功能目录
public fun catalog(): List<ImmutableCollectionsExample> = listOf(
example("list", "PersistentList", "persistentListOf(1, 2, 3).adding(4)", 4),
example("set", "PersistentSet", "persistentSetOf(\"a\", \"a\")", 1),
example("map", "PersistentMap", "persistentMapOf(...).putting(...)", 1),
example("hash-set", "PersistentHashSet", "persistentHashSetOf(...) ", 2),
example("hash-map", "PersistentHashMap", "persistentHashMapOf(...) ", 1),
// 转换、运算符、Builder、mutate、Adapter 和接口继续列出
)
功能目录的展示文字和自检结果由共享 Kotlin 生成,ArkTS 不对这些字符串做业务判断。
3.4 自检和错误边界
示例自检覆盖:
- persistent list 的原值保持不变;
- persistent set 会去重;
- persistent map 能按 key 返回新值;
- hash set/map 工厂可用;
- 标准集合可以转换为 persistent 集合;
+和-返回持久化结果;- Builder 可以生成快照;
mutate可以批量修改;- 目录覆盖全部主要功能;
- N-API 可以返回 JSON。
Native 异常统一转换为 {"error":"..."},C++ 在创建 ArkTS 字符串后立即调用 ImmutableCollectionsFree。
第 4 阶段:原生桥接(技术难点)
4.1 Kotlin/Native 对象不能直接交给 ArkTS
PersistentList、PersistentSet 和 PersistentMap 属于 Kotlin 运行时对象,不能把对象地址直接当成 JavaScript 对象使用。最终采用三层桥接:
ArkTS
│ JSON string
▼
C++ N-API entry
│ const char*
▼
Kotlin/Native C ABI
│ persistent collection implementation
▼
UTF-8 JSON + explicit free
4.2 方案对比
| 方案 | 优点 | 缺点 | 选用 |
|---|---|---|---|
| 直接导出 Kotlin 集合对象 | 代码少 | ABI、泛型和生命周期不可控 | ❌ |
| 只导出集合数量 | 实现简单 | 看不到真实 API 结果 | ❌ |
| C ABI + JSON | 边界清晰、易调试、易扩展 | 有一次序列化开销 | ✅ |
| 在 ArkTS 重写集合逻辑 | 页面简单 | KMP 与 ArkTS 容易产生两套实现 | ❌ |
4.3 Kotlin/Native 导出函数
@CName("ImmutableCollectionsCatalog")
public fun catalogNative(): CPointer<ByteVar> = response {
ImmutableCollectionsExamples.catalog()
.joinToString(prefix = "[", postfix = "]") { it.toJson() }
}
@CName("ImmutableCollectionsGet")
public fun getNative(index: Int): CPointer<ByteVar> = response {
ImmutableCollectionsExamples.get(index).toJson()
}
@CName("ImmutableCollectionsRunChecks")
public fun checksNative(): CPointer<ByteVar> = response { ... }
@CName("ImmutableCollectionsFree")
public fun freeNative(pointer: CPointer<ByteVar>?) {
if (pointer != null) nativeHeap.free(pointer.rawValue)
}
返回值使用 Native heap 分配的、以 0 结尾的 C 字符串。每一块缓冲区都由 Free 函数释放。
4.4 C++ N-API 方法分发
C++ 注册目录、读取、随机读取和自检方法:
napi_property_descriptor methods[] = {
{"getCatalog", nullptr, Catalog, nullptr, nullptr, nullptr,
napi_default, nullptr},
{"getImmutableCollections", nullptr, GetImmutableCollections,
nullptr, nullptr, nullptr, napi_default, nullptr},
{"randomImmutableCollections", nullptr, RandomImmutableCollections,
nullptr, nullptr, nullptr, napi_default, nullptr},
{"runChecks", nullptr, RunChecks, nullptr, nullptr, nullptr,
napi_default, nullptr},
};
getImmutableCollections 会检查参数数量、整数类型和非负范围,然后调用 ImmutableCollectionsGet。C++ 完成字符串转换后立即释放 Native 缓冲区。
4.5 CMake 加载动态库
add_library(immutablecollections SHARED IMPORTED)
set_target_properties(immutablecollections PROPERTIES
IMPORTED_LOCATION
"${CMAKE_CURRENT_SOURCE_DIR}/../../../libs/arm64-v8a/libimmutablecollections.so")
add_library(entry SHARED napi_init.cpp)
target_include_directories(entry PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/include")
target_link_libraries(entry PRIVATE immutablecollections libace_napi.z.so)
第 5 阶段:ArkUI 页面
5.1 ArkTS 客户端
export interface ImmutableCollectionsExample {
id: string;
kind: string;
value: string;
size: number;
}
export function catalog(): ImmutableCollectionsExample[] {
return JSON.parse(immutablecollectionsNative.getCatalog()) as ImmutableCollectionsExample[];
}
ArkTS 页面只把 JSON 映射为界面模型,不创建 Kotlin 集合,也不重新实现 adding、putting 或 mutate。
5.2 功能总览布局
标题区 immutablecollections / NATIVE READY
说明区 完整功能总览 · KMP / OpenHarmony
卡片区 12 类公开 API 和真实示例结果
状态区 10/10 公共检查通过
底部说明 Kotlin/Native → N-API → ArkTS
每张卡片显示功能名称、调用方式、结果和数量;用户打开应用即可直观看到这个三方库的功能边界。
5.3 页面与库的职责分离
页面负责:
- 调用
getCatalog; - 解析 JSON;
- 显示功能卡片;
- 显示 Native 自检状态;
- 处理错误文本和重新读取。
Kotlin 负责:
- 创建真实的 persistent/immutable/hash 集合;
- 执行转换、运算符、Builder 和 mutate;
- 生成功能描述和 JSON;
- 执行公共检查。
第 6 阶段:构建与验证
6.1 OpenHarmony Native 准备
./scripts/build-openharmony.sh
脚本会完成本地发布、示例测试、ohosArm64 编译、Native 动态库链接和头文件复制。
6.2 构建未签名 HAP
/Applications/DevEco-Studio.app/Contents/tools/hvigor/bin/hvigorw \
--mode module -p module=entry@default -p product=default \
-p buildMode=debug clean assembleHap --no-daemon
未签名产物:
example/ohosApp/entry/build/default/outputs/default/entry-default-unsigned.hap
6.3 签名工程和调试包
源码不保存证书和私钥。复制独立签名工程:
./scripts/prepare-signing-project.py /absolute/path/to/signing-project
配置 DevEco 签名后构建:
./scripts/build-hap.sh /absolute/path/to/signing-project
没有签名文件的 HAP 不能安装到真实鸿蒙设备;开发调试可以使用 DevEco 默认调试签名,正式发布必须使用开发者自己的证书和 profile。
四、完整代码对照
4.1 整体架构
ArkUI 页面
│ getCatalog / runChecks
▼
C++ N-API(libentry.so)
│ const char* JSON
▼
Kotlin/Native C ABI
│
libimmutablecollections.so
│
commonMain persistent collections
4.2 文件清单
| 文件 | 职责 |
|---|---|
core/commonMain/src/ImmutableList.kt | immutable/persistent list 接口 |
core/commonMain/src/ImmutableSet.kt | immutable/persistent set 接口 |
core/commonMain/src/ImmutableMap.kt | immutable/persistent map 接口 |
core/commonMain/src/extensions.kt | 工厂、转换、运算符和 mutate |
example/shared/.../ImmutableCollectionsExamples.kt | 功能目录、真实示例和自检 |
example/nativeApp/.../NativeBridge.kt | C ABI、JSON 返回和内存释放 |
example/ohosApp/.../ImmutableCollectionsClient.ets | N-API JSON 解析 |
example/ohosApp/.../Index.ets | 功能总览页面 |
example/ohosApp/entry/src/main/cpp/napi_init.cpp | N-API 导出和参数检查 |
scripts/build-openharmony.sh | 测试、Native 链接和产物复制 |
scripts/build-hap.sh | 签名工程 HAP 构建 |
docs/openharmony/VALIDATION.md | 构建和设备验收记录 |
4.3 关键 API 对照
| 层次 | API | 作用 |
|---|---|---|
| Kotlin | persistentListOf | 创建持久化列表 |
| Kotlin | persistentSetOf | 创建有序持久化集合 |
| Kotlin | persistentMapOf | 创建有序持久化映射 |
| Kotlin | persistentHashSetOf | 创建哈希持久化集合 |
| Kotlin | persistentHashMapOf | 创建哈希持久化映射 |
| Kotlin | adding / putting | 返回修改后的新集合 |
| Kotlin | toPersistent* | 转换标准集合 |
| Kotlin | builder / mutate | 批量修改并生成快照 |
| Native | ImmutableCollectionsCatalog | 返回功能目录 JSON |
| Native | ImmutableCollectionsGet | 返回单项 JSON |
| Native | ImmutableCollectionsFree | 释放 Native 字符串 |
| N-API | getCatalog | ArkTS 获取目录 |
| ArkTS | ForEach | 展示 12 类功能卡片 |
五、关键决策说明
决策 1:把 ohosArm64 加入公共构建约定
只有真正链接 ohosArm64 动态库,才能证明共享集合实现进入 OpenHarmony 运行时,而不是停留在页面字符串或 JVM 测试。
决策 2:示例通过 Maven 产物消费库
example/shared 解析本地发布产物,ohosApp 单独接收 .so 和头文件,避免根工程通过但 DevEco 无法打包。
决策 3:JSON 作为跨语言数据契约
JSON 让 ArkTS、C++ 和 Kotlin/Native 的边界清晰可调试,同时避免暴露 Kotlin 集合内部对象布局。
决策 4:页面展示真实 API 结果
功能总览中的每一项都对应 Kotlin 真实工厂函数或操作,页面只展示结果,避免把“演示 UI”误认为“库的实现”。
决策 5:构建产物和源码分离
.so、HAP、CMake 中间目录和 DevEco 缓存不提交 AtomGit;任何开发者都可以使用自己的 SDK 重新生成。
六、测试与验证
6.1 测试命令
# OpenHarmony 目标、Native 动态库和示例测试
./scripts/build-openharmony.sh
# 单独运行共享示例测试
(cd example && ./gradlew :shared:jvmTest -Pkotlin_Werror_override=disable)
# DevEco 未签名 HAP
cd example/ohosApp
/Applications/DevEco-Studio.app/Contents/tools/hvigor/bin/hvigorw \
--mode module -p module=entry@default -p product=default \
-p buildMode=debug clean assembleHap --no-daemon
6.2 验证结果
本次适配已经验证:
shared:jvmTest PASSED
compileKotlinOhosArm64 PASSED
linkDebugSharedOhosArm64 PASSED
nativeApp:prepareOhos PASSED
DevEco CompileArkTS PASSED
DevEco PackageHap PASSED
entry-default-unsigned.hap GENERATED
6.3 真机启动
hdc list targets
hdc -t <设备序列号> install -r \
example/ohosApp/entry/build/default/outputs/default/entry-default-signed.hap
hdc -t <设备序列号> shell aa start \
-a EntryAbility -b kotlinx.collections.immutable.sample
未签名包用于查看产物和 DevEco 构建结果;真机安装需要调试签名或正式签名包。
七、运行效果
7.1 功能总览真机效果图

截图中可以看到:
NATIVE READY表示页面已经加载 Native 动态库;- 页面标题明确显示 Kotlin Multiplatform/OpenHarmony;
PersistentList、PersistentSet、PersistentMap直接展示真实调用;PersistentHashSet和PersistentHashMap展示哈希实现;Immutable factories和Conversions展示工厂与转换能力;- 下方继续展示
+/- operators、Builder、mutate、Adapter 和接口体系; - 页面底部显示 Kotlin/Native、N-API 和 ArkTS 的完整调用链。
7.2 效果说明
页面不是一个普通的静态说明页。每个卡片由 Kotlin catalog() 生成,再由 Native C ABI 返回 JSON,最后由 ArkTS ForEach 渲染。重新读取会重新执行 Native 目录调用和公共自检。
7.3 命令速查
# 构建 Native 和生成头文件
./scripts/build-openharmony.sh
# 构建未签名 HAP
cd example/ohosApp
/Applications/DevEco-Studio.app/Contents/tools/hvigor/bin/hvigorw \
--mode module -p module=entry@default -p product=default \
-p buildMode=debug clean assembleHap --no-daemon
# 构建签名 HAP
./scripts/build-hap.sh /absolute/path/to/signing-project
八、遗留问题与改进方向
8.1 踩坑复盘
- 只改 ArkTS 页面不算 KMP 适配:必须把
commonMain集合实现真正编译成ohosArm64动态库。 - 不可变接口和持久化实现要分开说明:
Immutable*表达稳定契约,Persistent*提供返回新集合的修改操作。 - N-API 不负责集合业务:C++ 只做参数检查、字符串转换和释放,集合语义放在 Kotlin。
- 示例数据不能替代功能目录:页面应该展示工厂、转换、运算符、Builder 和 mutate 等完整能力。
- JDK 版本必须匹配:OpenHarmony Kotlin/Native 构建使用 JDK 21。
- 未签名 HAP 不能直接安装:设备安装需要 DevEco 调试签名或开发者自己的正式签名。
8.2 已知问题
- OpenHarmony
ohosArm64主要面向 ARM64 设备; - 老版本 Kotlin/Native 编译器可能提示上游返回值检查警告;
- Adapter 不会冻结底层标准集合,调用方仍需保证底层集合没有被其他引用修改;
- 功能总览用于验收主要 API,不替代完整 API 文档和契约测试;
- HAP 签名证书和 profile 依赖开发者本机环境。
8.3 未来优化方向
- 增加 Compose Multiplatform 业务页面,展示集合在状态管理中的实际用法;
- 增加更多泛型、嵌套集合和大数据量性能样例;
- 在持续集成中加入
ohosArm64链接和未签名 HAP 构建; - 增加 OpenHarmony 设备上的自动化启动和截图验收;
- 为 AtomGit 发布流程增加版本化 Native 产物和 API 兼容检查。
九、总结
9.1 核心难点回顾
本次适配真正需要处理的不是“在页面里显示一个列表”,而是一条完整跨端链路:
KMP commonMain 集合实现
→ ohosArm64 Kotlin/Native
→ libimmutablecollections.so
→ C ABI
→ C++ N-API
→ ArkTS JSON
→ ArkUI 功能总览
9.2 封装层次
- KMP 层:定义 immutable/persistent 接口、工厂和结构共享实现;
- Native 层:生成 ARM64 动态库,并通过 C ABI 输出有限入口;
- N-API 层:完成参数检查、字符串转换和 Native 内存释放;
- ArkTS 层:管理页面状态和功能卡片;
- DevEco 层:完成 CMake、ArkTS、HAP、签名和设备启动。
9.3 三条经验
- 先让真实集合 API 在 JVM 和 Native 通过,再接入 ArkUI;
- 用 JSON 和少量 C ABI 代替跨语言对象传递;
- 把自动测试、HAP 构建和真机安装分别记录,避免把“页面显示成功”误认为“库适配完成”。
9.4 适配成果
当前 kotlinx.collections.immutable 已完成:
ohosArm64Kotlin/Native 目标;- persistent/immutable/hash 集合在 OpenHarmony ARM64 上的编译;
- Kotlin/Native + C ABI + N-API 桥接;
- 12 类主要公开功能的 ArkUI 总览页面;
- JVM 测试、Native 链接、未签名 HAP 构建;
- DevEco 调试签名包的设备安装与启动;
- AtomGit 项目文档、效果图和 OpenHarmony 验收记录。
适配过程 FAQ
以下问题来自
ohosArm64目标接入、NAPI 桥接、HAP 构建与真机验收的实际流程,按出现频率排序。
Q1:DevEco Studio Sync 失败或 ohpm 依赖下载超时,怎么处理?
- 确认 DevEco Studio 版本与工程
build-profile.json5的compatibleSdkVersion一致; - 在
File > Settings > Build, Execution, Deployment > Ohpm配置可用的 ohpm 仓库镜像或代理; - 删除
oh_modules、oh-package-lock.json5与.hvigor缓存后重新 Sync; - 公司网络需要代理时,同时给 ohpm 与 hvigor 配置
http.proxy。
Q2:CMake 报 Missing .../libxxx.so 或找不到 Kotlin/Native 动态库?
- 先在
example目录执行./gradlew :nativeApp:linkDebugSharedOhosArm64(模拟器用linkDebugSharedOhosX64); - 确认
libxxx.so与libc++_shared.so已复制到ohos/entry/libs/<abi>/; - 检查
entry/build-profile.json5的abiFilters与设备 ABI 是否一致(真机arm64-v8a,模拟器x86_64); - 清理
entry/.cxx与entry/build后重试。
Q3:ArkTS 报 Cannot find module 'libxxx_napi.so' 或调用返回 undefined?
- 确认 CMake 的
add_library(<target> SHARED ...)名称与import ... from 'libxxx_napi.so'完全一致; - 解包 HAP,确认
libs/<abi>/libxxx_napi.so已打包; - 删除
entry/build、entry/.cxx与oh_modules后重新构建; - 检查
module.json5的srcEntry与页面路径是否正确。
Q4:真机安装报 signature verification failed 或 install failed?
- 在 DevEco Studio 的
Signing Configs配置证书、Profile 与密码; bundleName必须与签名 profile 中的 bundle name 一致;- 设备需加入 profile 的
deviceIds,调试证书有效期需覆盖当前时间; - 用
hdc list targets确认设备在线,再执行hdc install -r xxx-signed.hap。
Q5:应用启动白屏、闪退或 NAPI 调用崩溃?
- 用
hdc hilog | grep -i "napi\|kotlin"查看原生日志; - 确认
libc++_shared.so与 Kotlin/Native 工具链版本匹配,且 ABI 与设备一致; - 检查 C ABI 返回的字符串是否由 Native 侧分配、ArkTS 侧复制后是否调用
XxxFree释放; - 在 DevEco 的 Native 调试配置中附加
lldb,定位空指针与越界访问。
Q6:Gradle 报 ohosArm64 目标不存在或 Kotlin/Native 编译失败?
- 使用鸿蒙发行版 Kotlin(如
2.2.21-1.0.0),并在settings.gradle.kts配置 eazytec 仓库; - Gradle 建议 8.x、JDK 21,版本不匹配时先统一工具链;
- 确认
kotlin { ohosArm64() }已应用,且local.properties的 SDK 路径有效; - 清理
~/.gradle/caches中对应版本的 Kotlin/Native 缓存后重试。
Q7:HAP 构建报 SDK 版本不匹配或 compatibleSdkVersion 错误?
- 对齐 DevEco Studio、HarmonyOS SDK 与
build-profile.json5中的compatibleSdkVersion; - 升级 DevEco Studio 后同步升级 hvigor 与 SDK,避免
modelVersion与 IDE 不匹配; - 命令行构建时设置
DEVECO_SDK_HOME指向 DevEco 的sdk目录。
Q8:命令行 hvigor 构建失败,但 DevEco 里能构建?
- 使用 DevEco 自带的 node 与 hvigor:
"$DEVECO/Contents/tools/node/bin/node" "$DEVECO/Contents/tools/hvigor/bin/hvigorw.js" ...; - 设置
JAVA_HOME、NODE_HOME、DEVECO_SDK_HOME; - 加上
--no-daemon排除守护进程缓存影响,并清理entry/build与.hvigor。
参考文档
更多推荐


所有评论(0)