本文记录
AboutLibraries接入 OpenHarmony 的完整过程,覆盖 KMP 数据模型与解析内核盘点、ohosArm64/ohosX64目标、Kotlin/Native 动态库、C ABI/N-API 桥接、ArkUI 真机页面、HAP 构建、签名和真机验收。
AboutLibraries是与平台耦合度极低的 KMP"关于页面"三段式方案:构建期 Gradle 插件收集依赖元数据生成aboutlibraries.json,运行时aboutlibraries-core解析为Library/License实体,再由 Compose UI 展示。本次适配让数据模型与解析内核这一公共实现进入 OpenHarmony ARM64 运行时,ArkUI 页面作为真机验收宿主,Compose Multiplatform(CMP)应用可以通过同一个 KMP 依赖使用这些解析 API。
项目地址:AtomGit/oh-tpc/AboutLibraries
上游仓库:mikepenz/AboutLibraries
开发工具:华为云码道
环境安装:环境安装指南
一、背景
1.1 为什么做 OpenHarmony 平台 KMP/CMP 适配
AboutLibraries为 Kotlin 项目提供依赖元数据的构建期收集(com.mikepenz.aboutlibraries.plugin插件)、运行时解析(aboutlibraries-core的Libs.Builder().withJson(json).build())和 Compose 渲染(aboutlibraries-compose-m2/m3)三层能力。KMP 项目通常把解析层放在commonMain,由 Android、iOS、桌面、Web 或其他 Native 宿主共享。OpenHarmony 应用同样需要"开源许可页"这套公共能力,但默认构建并不会生成 OpenHarmony 的 Kotlin/Native 变体。
如果只把示例页面改成 ArkTS,页面可以显示列表,却无法证明公共解析实现已经在 OpenHarmony ARM64 设备上完成编译、链接和执行。适配需要同时验证 KMP 核心、Native 动态库、C ABI、N-API、ArkUI 页面和 HAP 交付链路。
| 障碍 | 具体问题 |
|---|---|
| 目标缺失 | 必须增加ohosArm64()/ohosX64()才能生成 OpenHarmony KLIB。 |
| 工具链不一致 | 上游使用 Gradle 9 / AGP 9 / Compose 1.12 / Kotlin 2.4,鸿蒙侧工具链为 Kotlin2.2.21-1.0.0/ Gradle 8.14.1。 |
| 语言边界不同 | ArkTS 不能直接持有 Kotlin 对象,需要 C ABI、C++ N-API 和 JSON。 |
| 序列化缺位 | aboutlibraries-core依赖 kotlinx.serialization 解析 JSON,该库无 ohos 制品。 |
| 语义必须保持 | 名称排序、许可证按 hash 去重、坏 JSON 吞异常返回空结果,都是上游契约。 |
| 交付链路复杂 | .so、CMake、N-API、HAP、签名和hdc都要单独验收。 |
因此,本项目把边界放在 KMP 目标配置、内核 1:1 提取、C ABI/N-API 桥接和 ArkUI 验收层。解析语义仍由公共实现负责,ArkTS 只负责调用 Native、解析 JSON 和展示结果。
1.2 库提供的能力
上游三段式中,构建期插件与 UI 层分别工作在构建机和 Compose 宿主上,本次适配的对象是中间的解析内核。示例提供四个可观察场景:
- 库列表:解析
aboutlibraries.json得到全部Library,按上游语义排序展示; - 许可证:按许可证分组统计,点击读取许可证全文(内嵌 Apache-2.0 全文约 11 KB);
- 搜索:在 Native 侧按名称 / 坐标 / 描述过滤库;
- 状态:版本握手、解析统计和三个错误路径演示。
Library实体包含:
| 字段 | 作用 |
|---|---|
uniqueId | 依赖坐标(groupId:artifactId,去版本)。 |
artifactVersion | 版本,可空。 |
name/description/website | 名称、描述、网站。 |
developers/organization | POM 中的开发者和组织。 |
scm | 源码仓库信息,url非空即视为开源。 |
licenses | 许可证集合,以 hash 关联顶层许可证表。 |
funding | 资助信息(GitHub Sponsors 等)。 |
tag/targets | 分组标签与消费该产物的 Kotlin target 集合。 |
解析层还提供五项派生查询:search、licenses、groupByLicense、stats和licenseContent,全部在 Kotlin 侧完成。
1.3 实现适配
| 维度 | 要求 |
|---|---|
| 代码复用 | aboutlibraries-core数据模型与解析逻辑 1:1 提取到 KMPcommonMain(同包名同文件名)。 |
| 平台目标 | 独立 example 工程增加ohosArm64+ohosX64,生成双 ABI 动态库。 |
| 桥接稳定 | 使用 3 个 C ABI 和 UTF-8 JSON,不传递 Kotlin 对象地址。 |
| CMP 兼容 | CMP 应用复用同一 KMP 依赖;ArkUI 只负责真机验收,Compose UI 待社区工具链对齐后接回。 |
| UI 完整 | 支持库列表、详情展开、许可证全文、搜索、统计和错误展示。 |
| 仓库规范 | 项目说明、文章、效果图和源码链接统一使用 AtomGit。 |
本项目的 ArkUI 页面不是 Compose Multiplatform UI 实现。CMP 工程可以直接依赖 OpenHarmony KMP 变体,在自己的 Compose 页面中使用标准
Libs.Builder()解析 API。
二、实现路线图
第 1 阶段:项目初始化 ── 盘点源集、工程边界和 OpenHarmony 交付物 第 2 阶段:目标与依赖打通 ── 独立 example 工程、ohosArm64/ohosX64 与 so 交接 第 3 阶段:内核提取建模 ── core 1:1 提取、MiniJson 解析器和黄金测试 第 4 阶段:原生桥接 ── C ABI、C++ N-API、参数校验和内存释放 第 5 阶段:ArkUI 宿主 ── 四 Tab 页面、真实 Native 数据和错误边界 第 6 阶段:示例与验证 ── HAP、签名、设备安装、真机运行和效果图三、逐步实现过程
第 1 阶段:项目初始化
1.1 工程边界
AboutLibraries/ 上游仓库原样保留(根构建一行不改) example/ 独立 Gradle 工程(自带 wrapper) ├── nativeApp/ 内核提取、MiniJson、C ABI 桥和 JVM 测试 └── harmonyApp/ DevEco Stage、CMake N-API 和 ArkTS 页面 doc/ 适配文章与真机效果图example是独立 Gradle 工程,不把 DevEco 工程作为根项目的 Kotlin 子模块,Gradle 和 Hvigor 可以分开执行;上游根构建依赖远程 convention 插件与 AGP 9 / Kotlin 2.4 版本线,保持原样互不干扰,审核面上只有新增文件。
1.2 工具链矩阵
| 项目 | 配置 |
|---|---|
| Kotlin Multiplatform | OpenHarmony 工具链2.2.21-1.0.0(社区 Maven) |
| JDK | 21 |
| Gradle | 8.14.1(example wrapper 钉死) |
| OpenHarmony 目标 | ohosArm64+ohosX64 |
| DevEco product | 6.0.1(21) |
| DevEco Studio | 6.0.1 Release |
| ABI | arm64-v8a+x86_64 |
| Bundle | com.mikepenz.aboutlibraries.ohos |
exportJAVA_HOME="/path/to/jdk-21"java-version1.3 页面边界
标题区 ABOUTLIBRARIES · OPENHARMONY / 版本握手行 Tab 区 库 / 许可证 / 搜索 / 状态 库列表区 名称、版本、许可证徽章、runtime/build 标签,点击展开全字段 许可证区 许可证分组列表 + 元数据 + 全文滚动阅读 搜索区 关键字输入 + native 过滤结果 状态区 版本、统计、target 覆盖和三个错误路径演示按钮页面启动时通过aboutLibrariesVersion()完成握手,读取 rawfile 中内置的aboutlibraries.json后交给 Native 解析,自动填充库列表与许可证分组。
第 2 阶段:目标与依赖打通
2.1 仓库置顶与独立工程
pluginManagement{repositories{// HarmonyOS Kotlin 工具链仓库必须排在最前,// 否则插件解析回落官方 Kotlin,ohosArm64() 无从解析maven("https://maven.eazytec-cloud.com/nexus/repository/maven-public/")maven("https://maven.eazytec-cloud.com/nexus/content/groups/harmonyos")gradlePluginPortal()google()mavenCentral()}}rootProject.name="ohos_aboutlibraries"include(":nativeApp")2.2 构建 Native 产物并交接
kotlin{applyDefaultHierarchyTemplate()jvm()// 保留 JVM 目标承载黄金交叉验证ohosArm64{binaries.sharedLib{baseName="ohosaboutlibraries"}}ohosX64{binaries.sharedLib{baseName="ohosaboutlibraries"}}}链接任务finalizedBy拷贝任务,把libohosaboutlibraries.so与对应 triple 的libc++_shared.so自动放入harmonyApp/entry/libs/{arm64-v8a,x86_64}/:
./gradlew :nativeApp:linkDebugSharedOhosArm64 :nativeApp:linkDebugSharedOhosX64 ./gradlew :nativeApp:jvmTest2.3 零第三方依赖的提取层
sourceSets{commonMain.dependencies{}// 提取层零第三方依赖}kotlinx.serialization 没有 ohos 制品,提取层不引入任何序列化库,JSON 解析由自带的 MiniJson 完成(第 3 阶段)。
第 3 阶段:内核提取与语义建模(技术难点)
3.1 JSON 契约
aboutlibraries.json(HAP rawfile) ↓ ArkTS 读取文本 Libs.Builder().withJson(json).build() ↓ parseData(上游语义) MiniJson 递归下降解析 ↓ Result(libraries, licenses) Bridge.kt 派生查询 ↓ UTF-8 JSON N-API aboutLibrariesParse/Query ↓ ArkUI Index.ets 四 Tab 页面页面不复制任何解析逻辑,每个字段由提取的公共 Kotlin 代码生成。
3.2 内核 1:1 提取
上游aboutlibraries-core约 605 行、15 个文件,全部为平台无关纯 Kotlin。提取规则:同包名同文件名,文件头注释标明上游路径与差异,可逐文件 diff 复核:
| 上游文件 | 处置 |
|---|---|
commonMain/.../Libs.kt与entity/*.kt(8 文件) | 1:1 复制,仅剥离@Serializable/@SerialName注解 |
multiplatformMain/.../MultiplatformParser.kt+MultiplatformExtensions.kt | 与commonMain/.../Parser.kt合并为单一声明,getJSONObject/optString/forEachObject/forEachString等 helper 命名与上游一一对应 |
androidMain/**(org.json 实现) | 不提取 |
funparseData(json:String):Result{try{valmetaData=MiniJson.parse(json).let{itasMiniJson.Node.Obj}vallicenses=metaData.getJSONObject("licenses").forEachObject{key->License(getString("name"),optString("url"),optString("year"),optString("spdxId"),optString("content"),key)}// ……与上游 actual 逐行同构}catch(t:Throwable){println("Failed to parse the meta data *.json file:$t")}returnResult(emptyList(),emptyList())// 上游吞异常语义原样保留}3.3 MiniJson 解析器
aboutlibraries.json是深嵌套文档(licenses还是以 hash 为键的对象表),平面解析器无法胜任,因此 MiniJson 实现了完整语法:对象 / 数组 / 字符串 / 数字 / 布尔 / null、全部转义序列、LinkedHashMap保持键序;约 190 行、零依赖、commonMain单文件,JVM 与 ohos 两侧编译同一份。
3.4 黄金交叉验证
jvmTest用与 HAP rawfile 同一份 JSON 钉住上游数值:8 库 / 3 许可证、按小写名称排序、artifactId拼接、许可证按 hash 去重(Apache-2.0 被多个库共享但集合只有一条)、缺版本时坐标带尾冒号、坏 JSON 返回空结果、MiniJson 转义与畸形输入行为,共 13 个用例。
第 4 阶段:原生桥接
4.1 三层桥接
ArkTS │ JSON string ▼ C++ N-API entry │ const char* ▼ Kotlin/Native C ABI │ Libs.Builder / 派生查询 ▼ UTF-8 JSON + DisposeString直接导出 Kotlin 对象会暴露 ABI 和生命周期问题;只导出整数又会让页面复制解析语义,所以选择 C ABI + JSON。
4.2 Kotlin/Native 导出函数
@CName("AboutLibrariesVersion")funaboutLibrariesVersion():String// 版本握手@CName("AboutLibrariesParse")funaboutLibrariesParse(request:String):String// {"json": "<aboutlibraries.json>"} → counts + libraries + licenses 摘要@CName("AboutLibrariesQuery")funaboutLibrariesQuery(request:String):String// {"op": "search|licenses|groupByLicense|stats|licenseContent", ...}每个导出整体 try/catch,响应统一为{"ok":true,...}或{"ok":false,"error":"..."},Kotlin 异常绝不跨 FFI 边界;相同 JSON 文本复用会话缓存,派生查询无需重复解析。
4.3 C++ N-API 方法分发
napi_property_descriptor desc[]={{"aboutLibrariesVersion",nullptr,NapiVersion,nullptr,nullptr,nullptr,…,nullptr},{"aboutLibrariesParse",nullptr,NapiParse,nullptr,nullptr,nullptr,…,nullptr},{"aboutLibrariesQuery",nullptr,NapiQuery,nullptr,nullptr,nullptr,…,nullptr},};N-API 只负责参数类型检查、字符串转换和释放,不实现解析语义。KN 返回字符串创建 ArkTS 字符串后,立即经libohosaboutlibraries_symbols()->DisposeString归还 Kotlin 运行时,绝不free()。
4.4 CMake 和类型声明
add_library(ohosaboutlibraries SHARED IMPORTED) set_target_properties(ohosaboutlibraries PROPERTIES IMPORTED_LOCATION "${CMAKE_CURRENT_SOURCE_DIR}/../../../libs/${OHOS_ARCH}/libohosaboutlibraries.so" IMPORTED_NO_SONAME TRUE) add_library(aboutlibraries_napi SHARED napi_init.cpp) target_link_options(aboutlibraries_napi PRIVATE "-Wl,-rpath,\$ORIGIN") target_link_libraries(aboutlibraries_napi PUBLIC libace_napi.z.so libhilog_ndk.z.so ohosaboutlibraries)exportconstaboutLibrariesVersion:()=>string;exportconstaboutLibrariesParse:(request:string)=>string;exportconstaboutLibrariesQuery:(request:string)=>string;第 5 阶段:ArkUI 宿主
5.1 加载数据
import{aboutLibrariesVersion,aboutLibrariesParse,aboutLibrariesQuery}from'libaboutlibraries_napi.so';import{util}from'@kit.ArkTS';constcontext=this.getUIContext().getHostContext();constraw=context.resourceManager.getRawFileContentSync('aboutlibraries.json');consttext=util.TextDecoder.create('utf-8').decodeToString(raw);constreq:Record<string,string>={'json':text};constmodel=JSON.parse(aboutLibrariesParse(JSON.stringify(req)))asParseInfo;this.libraries=model.libraries??[];5.2 页面交互
页面支持库列表(点击展开上游全部字段,含 funding / organization / scm / targets)、许可证分组与全文阅读、native 搜索和状态统计。所有数据来自共享 Kotlin 结果,ArkTS 不重新实现排序、去重或过滤。
5.3 对比度和错误边界
选中项使用深蓝底白字,标签徽章用浅色底深色字,错误横幅为红底白字。状态页提供三个错误路径演示按钮(坏 JSON / 未知 op / 坏 hash),任何输入下页面不崩溃,错误显示在状态行。
第 6 阶段:示例与验证
6.1 工程结构
example/ ├── nativeApp/src/ │ ├── commonMain/.../com/mikepenz/aboutlibraries/ # 内核 1:1 提取(8 文件) │ ├── commonMain/.../example/nativeapp/MiniJson.kt │ ├── jvmTest/.../GoldenJsonTest.kt + MiniJsonTest.kt │ └── ohosMain/.../example/nativeapp/Bridge.kt └── harmonyApp/entry/src/main/ ├── cpp/CMakeLists.txt + napi_init.cpp + include/libohosaboutlibraries_api.h ├── ets/pages/Index.ets └── resources/rawfile/aboutlibraries.json6.2 构建、签名和安装
exportJAVA_HOME="/path/to/jdk-21"cdexample ./gradlew :nativeApp:linkDebugSharedOhosArm64 :nativeApp:linkDebugSharedOhosX64# DevEco Studio 打开 example/harmonyApp → Signing Configs → 自动生成签名hvigorw assembleHap--modemodule-pproduct=default-pbuildMode=debughdc list targets-vhdc-t<设备序列号>install-r\entry/build/default/outputs/default/entry-default-signed.hap hdc-t<设备序列号>shell aa start\-aEntryAbility-bcom.mikepenz.aboutlibraries.ohos-mentry四、完整代码对照
4.1 整体架构
Parser.kt(上游解析语义 + MiniJson) │ parseData / Libs.Builder ▼ Bridge.kt │ AboutLibrariesVersion / Parse / Query ▼ libaboutlibraries_napi.so │ aboutLibrariesVersion / Parse / Query ▼ Index.ets │ JSON parse + state update ▼ ArkUI 真机页面(库 / 许可证 / 搜索 / 状态)4.2 文件清单
| 文件 | 职责 |
|---|---|
example/settings.gradle.kts | 工具链仓库置顶、独立工程边界 |
example/nativeApp/build.gradle.kts | ohosArm64/ohosX64sharedLib 与 so 拷贝 |
nativeApp/.../aboutlibraries/**(8 文件) | core 1:1 提取(同包名同文件名) |
nativeApp/.../MiniJson.kt | 零依赖 JSON 解析与转义 |
nativeApp/.../GoldenJsonTest.kt | 上游语义黄金断言 |
nativeApp/.../Bridge.kt | C ABI、会话缓存和派生查询 |
harmonyApp/.../napi_init.cpp | N-API 导出、hilog 和 DisposeString |
harmonyApp/.../CMakeLists.txt | IMPORTED KN so 与 rpath |
harmonyApp/.../Index.ets | ArkUI 四 Tab 验收页面 |
README.OpenHarmony_CN.md | 适配主文档(5000+ 字) |
4.3 关键 API 对照
| 层次 | API | 作用 |
|---|---|---|
| KMP | Libs.Builder().withJson().build() | 解析 JSON 并按上游语义排序去重 |
| KMP | parseData | JSON →Result(libraries, licenses) |
| Native | AboutLibrariesVersion | 版本握手 |
| Native | AboutLibrariesParse | 返回完整模型 |
| Native | AboutLibrariesQuery | search / licenses / groupByLicense / stats / licenseContent |
| N-API | aboutLibrariesParse/aboutLibrariesQuery | 向 ArkTS 暴露数据 |
| ArkTS | loadAndParse/doSearch | 触发解析并刷新 UI |
4.4 ArkTS 与 Kotlin 的边界
constmodel=JSON.parse(aboutLibrariesParse(JSON.stringify(req)))asParseInfo;@CName("AboutLibrariesParse")funaboutLibrariesParse(request:String):String两者之间只传输 JSON 字符串,不传输 Kotlin 对象或未校验的动态结构。
五、关键决策说明
决策 1:上游根构建一行不改,example 独立成工程
上游版本线(Gradle 9 / AGP 9 / Kotlin 2.4)与鸿蒙工具链不兼容,改动根构建会引入不可审计的 diff。独立 example 工程让适配面只有新增文件。
决策 2:内核 1:1 提取而不是重写
同包名同文件名提取让每一份副本都能与上游 diff 复核;文件头注释声明差异(仅剥序列化注解),解析语义的"没有漂移"由黄金测试背书。
决策 3:MiniJson 零依赖替代 kotlinx.serialization
工具链无 ohos 制品,自写 190 行完整语法解析器比引入不可控垫片更可审计;JVM 与 ohos 编译同一份源码,行为一致性由 13 个测试用例钉住。
决策 4:JSON 作为跨语言数据契约 + 会话缓存
JSON 让 ArkTS、C++ 和 Kotlin/Native 的边界清楚可调试;Parse携带全文时重建会话,相同文本直接复用,派生查询不重复解析。
决策 5:ArkUI 作为验收宿主,CMP 复用 KMP 解析内核
当前页面验证 OpenHarmony Native 链路;上游 Compose 模块源码原样保留,待社区 CMP 的 ohos 制品与上游版本对齐后接回,届时 ArkUI 页面退化为验收工具。
六、测试与验证
6.1 测试环境
本次验证使用 macOS(Apple Silicon)、JDK 21、DevEco Studio 6.0.1 Release、OpenHarmony SDK6.0.1(21)与华为真机(arm64-v8a)。
6.2 共享样例测试
cdexample ./gradlew :nativeApp:jvmTest13 个用例(7 黄金 + 6 MiniJson)全部通过,验证库数量与排序、许可证 hash 去重、artifactId拼接、可空字段回退、坏 JSON 空结果、转义序列和畸形输入拒绝。
6.3 符号与 HAP 验证
AboutLibrariesParse / AboutLibrariesQuery / AboutLibrariesVersion / libohosaboutlibraries_symbols → llvm-nm -D 全局 T 符号(双 ABI) CompileArkTS: finished PackageHap: finished BUILD SUCCESSFUL install bundle successfully start ability successfully未签名 HAP(约 6.5 MB)解包含双 ABI 六件 so(NAPI so + KN so + libc++_shared.so × 2)。
6.4 功能用例
- 启动后自动完成版本握手并加载 8 个库、3 个许可证;
- 库列表点击展开上游全部字段(描述、坐标、开发者、组织、SCM、targets、资助);
- 许可证 Tab 分组浏览,Apache-2.0 全文(约 11 KB)可滚动阅读;
- 搜索
kotlin命中 1 项、aboutlibraries命中 2 项,过滤在 Native 侧执行; - 状态页显示解析耗时与 target 覆盖(jvm / ohosArm64 / ohosX64);
- 坏 JSON / 未知 op / 坏 hash 三个演示按钮均返回明确错误文案,页面不崩溃。
6.5 验证结论
Native 动态库、C ABI、N-API、ArkUI 页面和签名 HAP 已完成链路验证。应用在真机上成功安装并进入前台,页面展示了真实解析结果的库列表、许可证分组与统计信息。
七、运行效果
7.1 真机截图
7.2 命令速查
gitclone https://atomgit.com/oh-tpc/AboutLibraries.gitcdAboutLibraries/exampleexportJAVA_HOME="/path/to/jdk-21"./gradlew :nativeApp:linkDebugSharedOhosArm64 :nativeApp:linkDebugSharedOhosX64 ./gradlew :nativeApp:jvmTestcdharmonyApp hvigorw assembleHap--modemodule-pproduct=default-pbuildMode=debug hdc-t<设备序列号>install-r\entry/build/default/outputs/default/entry-default-signed.hap八、遗留问题与改进方向
8.1 踩坑复盘
- 工具链仓库必须写在
pluginManagement最前,否则ohosArm64()报Unresolved reference; String.format在 Kotlin/Native 不存在,\uXXXX转义改为手写十六进制拼接;libc++_shared.so不随 KN so 产出,必须从 Konan 依赖目录拷入entry/libs/<abi>/,否则 HAP 安装报 9568347;- hvigor 的
signingConfigs不接受空骨架,提交版直接整体去掉签名块,证书留在本机; - ArkTS 中 Native 函数返回值不要先赋局部变量(推断为 any),直接嵌套
JSON.parse(...) as X; - 运行结果要来自真实 Native 调用,而不是页面静态文字;
- 签名工程必须与源码分离,证书不能进入 AtomGit。
8.2 已知问题
- 上游 Compose UI 模块(
aboutlibraries-compose*)未编译进鸿蒙,由 ArkUI 页面替代演示; - MiniJson 只实现本库用到的 JSON 读取语法,不含 streaming / schema 校验;
- Demo 的
aboutlibraries.json按插件 schema 手工构建(描述本 HAP 真实供应链),生产业务应运行上游 Gradle 插件生成同名文件替换; - 上游 Gradle 插件可照常在构建机工作,但未接入 hvigor 工程自动生成 rawfile;
aboutlibraries-compose-wear-m3为纯 Android 模块,与鸿蒙无关,未处理。
8.3 未来优化方向
- 跟踪社区 CMP 的 ohos 制品版本,把上游 Compose UI 模块接回鸿蒙宿主;
- 评估 klib / Maven 制品发布路径,替代 so + NAPI 交付形态;
- 在 CI 中加入 Native 链接、ELF 符号检查和 HAP 构建;
- 补充不同设备 ABI、API 版本的验收矩阵;
- 为 hvigor 工程写插件接线脚本,自动生成并同步
aboutlibraries.json。
九、总结
9.1 核心难点回顾
KMP commonMain 解析内核(1:1 提取) → ohosArm64/ohosX64 Kotlin/Native → C ABI → C++ N-API → ArkTS JSON 解析 → ArkUI 真机页面9.2 封装层次
- KMP 层:提供
Libs.Builder、Library/License实体和上游解析语义(排序、hash 去重、容错); - Native 层:生成双 ABI 动态库并通过 3 个 C ABI 输出 JSON;
- N-API 层:完成参数检查、字符串转换和 Native 内存释放;
- ArkTS 层:管理列表、许可证、搜索、统计和错误状态;
- DevEco 层:完成 CMake、HAP、签名、安装和真机运行。
9.3 三条经验
- 先让解析内核在 KMP 与 Native 侧通过黄金测试,再接入 ArkUI 或 CMP UI;
- 用 JSON 和少量 C ABI 代替跨语言对象传递,并明确字符串释放责任;
- 分别记录自动测试、Native 链接、HAP 构建和真机运行,避免把编译成功误认为设备链路可用。
9.4 适配成果
当前适配已完成:
aboutlibraries-core数据模型与解析内核的 1:1 提取(ohosArm64+ohosX64双目标);- 13 个 JVM 黄金交叉验证用例全部通过;
- 3 个 C ABI 符号和 C++ N-API 包装(
llvm-nm -D全局 T 符号验证); - DevEco Stage ArkUI 四 Tab 验收页面;
- HAP 构建、双 ABI 三件套 so、签名安装和真机运行验证;
- AtomGit 项目文档(README 四件套)、适配文章和本地效果图。
适配过程 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。
参考文档
- AtomGit/oh-tpc/AboutLibraries
- mikepenz/AboutLibraries(上游)
- Kotlin Multiplatform
- Compose Multiplatform
- OpenHarmony N-API
- DevEco Studio
- OpenHarmony ArkUI