本文记录 WhatIf 接入 OpenHarmony 的完整过程,覆盖 KMP/CMP 工程盘点、
ohosArm64 目标、Kotlin/Native 动态库、C ABI/N-API 桥接、ArkUI 示例页面、
HAP 构建、签名准备和验证记录。

WhatIf 是一个用于简化 Kotlin 条件判断、空值处理、字符串/数组/集合判断和
Boolean 逻辑的 Kotlin Multiplatform 库。本次适配复用原有 commonMain 扩展函数,
由 Kotlin/Native 生成 ARM64 动态库,再通过 C ABI、C++ N-API 和 ArkTS 页面展示
同一份共享 Kotlin 代码的执行结果。

项目地址: AtomGit/oh-tpc/WhatIf

开发工具: 华为云码道

一、背景

1.1 为什么做开源鸿蒙平台 KMP/CMP 适配

WhatIf 原本是一个 Kotlin Multiplatform 扩展库,公共 API 位于
whatif/src/commonMain。它不依赖 Android UI 或 JVM 运行时,适合把同一套条件
表达式复用于 Android、iOS、桌面和 Native 工程。

如果只把页面重新写成 ArkTS,再在页面中手写几个 if 判断,页面可以显示结果,
但无法证明 WhatIf 的 Kotlin 公共 API 已经进入 OpenHarmony Native 运行时。本次
适配需要同时解决以下问题:

障碍具体问题
目标缺失原 KMP 模块没有 ohosArm64(),无法生成 OpenHarmony KLIB。
工具链不一致Kotlin/Native、Gradle、OpenHarmony LLVM 和 Native SDK 必须匹配。
公共 API 边界扩展函数是 inline/common API,需要在 Native 编译器上保持语义一致。
语言边界不同ArkTS 不能直接持有 Kotlin data class,需要经过 C ABI、C++ N-API 和 JSON。
内存生命周期Kotlin/Native 返回的字符串必须由明确的 Free 函数释放。
示例可验证性需要在 JVM、Native、CMake、ArkTS 和 HAP 层分别留下可重复的检查。
交付链路复杂ARM64 动态库、HAP、签名、设备安装和依赖检查需要分阶段验证。

因此,本项目把适配边界放在三个地方:KMP 目标配置、C ABI/N-API 桥接层和 ArkUI
展示层。WhatIf 的判断语义仍由 Kotlin 共享代码维护,ArkTS 只负责调用 Native
方法、解析 JSON 和展示检查状态。

1.2 库提供的能力

WhatIf 公共模块提供以下能力:

  • whatIf:条件为 true 时执行代码,并返回原始对象;
  • whatIfMap:根据条件或对象是否为空返回不同类型的结果;
  • whatIfNotNull:接收对象非空时执行分支;
  • whatIfNotNullAs:非空且可以安全转换为目标类型时执行分支;
  • whatIfNotNullOrEmpty:处理字符串、数组、List、Set 和 Map;
  • addWhatIfNotNull、addAllWhatIfNotNull:按条件向可变集合添加元素;
  • removeWhatIfNotNull、removeAllWhatIfNotNull:按条件删除集合元素;
  • whatIfElse:可空 Boolean 为 false 时执行分支;
  • whatIfAnd、whatIfOr:组合 Boolean 或 Boolean 集合的判断结果。

示例 facade 将这些 API 组织为四个可展示场景:

场景实际调用页面含义
条件执行whatIf(true)true 分支被执行
空值映射whatIfMap(default = ...)null 安全返回默认值
集合扩展List、Array、String 的 whatIfNotNullOrEmpty非空数据进入回调
布尔扩展whatIfElse、whatIfAnd、whatIfOrBoolean 条件组合

公共 facade 另外执行 8 项检查,JVM 测试和 OpenHarmony Native 桥接共用同一组
检查函数,避免测试代码与页面代码各自实现一套判断。

1.3 实现适配

维度要求
代码复用条件、空值、集合和 Boolean 语义全部来自原始 commonMain。
平台目标为 whatif 和示例模块加入 ohosArm64,生成 libwhatif.so。
桥接稳定使用少量 C ABI 函数和 UTF-8 JSON,不暴露 Kotlin 对象地址。
UI 完整页面展示当前场景、返回值、能力列表和公共检查状态。
可测试JVM 测试、Native 链接、ELF 依赖、HAP 构建分别验收。
签名安全仓库只保留签名工程准备脚本,证书和密钥由开发者本机配置。
仓库规范项目说明、文章、效果图和源码链接统一使用 AtomGit。

本项目的 ArkUI 页面是独立的验证宿主,公共 API 仍然保持平台无关。其他
KMP/CMP 应用可以直接复用 WhatIf 的 Kotlin 扩展,不需要依赖 ArkTS 页面。

二、实现路线图

第 1 阶段:项目初始化     ── 盘点 KMP API、测试和 OpenHarmony 示例边界
第 2 阶段:目标与依赖打通 ── 加入 ohosArm64、独立 example 工程和 Native 任务
第 3 阶段:行为与序列化   ── 建立 WhatIfExamples、JSON 记录和八项公共检查
第 4 阶段:原生桥接       ── Kotlin/Native C ABI、C++ N-API、内存释放和类型检查
第 5 阶段:ArkUI 宿主     ── ArkTS Native 客户端、页面状态和刷新交互
第 6 阶段:示例与验证     ── HAP 构建、签名准备、依赖检查和效果图

每个阶段都使用真实产物作为下一阶段输入:先用 JVM 验证共享 WhatIf 行为,再把
相同代码链接为 ARM64 动态库,随后由 CMake 和 N-API 加载到 Stage 工程,最后
构建未签名 HAP 并检查包内的 Native 库。

三、逐步实现过程

第 1 阶段:项目初始化

1.1 盘点公共 API 和工程边界

项目采用与参考 KMP/CMP 工程一致的分层:

whatif/                       KMP 条件扩展、空值扩展、集合扩展和 Boolean 扩展
example/shared/               公共 facade 和 JVM 验收测试
example/nativeApp/            ohosArm64 Kotlin/Native 动态库
example/ohosApp/              DevEco Stage 工程和 ArkUI 页面
scripts/                      Native、HAP、签名工程和依赖检查脚本
docs/openharmony/             OpenHarmony 验证说明和效果图

example 是独立 Gradle 工程,不把 DevEco 工程当作 Kotlin 子模块。这样可以分别
执行 Gradle 和 Hvigor,也可以把 ohosApp 复制到仓库外后在 DevEco Studio 中
配置签名。

1.2 固定工具链和版本矩阵

本项目使用以下版本约定:

项目配置用途
Kotlin Multiplatform2.2.21-1.0.0JVM、Kotlin/Native 和 KLIB
JDK21Gradle、Kotlin 编译和 Native 任务
OpenHarmony 目标ohosArm64ARM64 真机动态库
DevEco product6.0.0(20)Stage 工程兼容和目标版本
ABIarm64-v8aHAP 原生库架构
WhatIf 版本1.2.2公共 API 和 Maven 坐标

执行 Gradle 脚本前先选择 JDK 21:

export JAVA_HOME="/path/to/jdk-21"
export PATH="$JAVA_HOME/bin:$PATH"
java -version

JDK 25 会让当前 Kotlin 编译器在解析 Java 版本时失败,因此构建脚本明确要求
JDK 21。设备是否为 ARM64 也要单独确认,宿主构建成功不能替代设备检查。

1.3 创建 OpenHarmony 示例目录

示例页面围绕“当前场景、执行结果、能力列表和公共检查”组织:

标题区          WhatIf 工作台 / Kotlin Multiplatform + OpenHarmony
状态区          NATIVE READY
当前场景        条件执行、空值映射、集合扩展或布尔扩展
结果区          detail 文本和重新运行检查按钮
能力区          四个真实 WhatIf 场景,可点击切换
自检区          8/8 公共检查通过

页面不把扩展函数重新实现成 ArkTS 条件判断。用户点击场景时,ArkTS 只改变当前
记录;重新运行检查时,调用 Native 的 runChecks(),由 Kotlin facade 返回结果。

第 2 阶段:目标与依赖打通

2.1 加入 ohosArm64 目标

根模块在原有 JVM、Android 和 Apple 目标基础上增加 OpenHarmony Native:

kotlin {
  listOf(
    iosX64(),
    iosArm64(),
    iosSimulatorArm64(),
    macosArm64(),
    macosX64(),
  ).forEach {
    it.binaries.framework { baseName = "common" }
  }

  androidTarget {
    publishLibraryVariants("release")
  }

  ohosArm64()
  jvm { compilerOptions.jvmTarget.set(JvmTarget.JVM_17) }
}

这样 whatif/src/commonMain 的扩展函数可以直接参与 compileKotlinOhosArm64,
不需要复制一份平台专用实现。

2.2 Native focused build 的作用

example/nativeApp 构建一个受 linker map 约束的 shared library:

kotlin {
  ohosArm64 {
    binaries.sharedLib {
      baseName = "whatif"
      linkerOpts(
        "--entry=0",
        "--version-script=${project.file("src/ohosArm64Main/linker/shared-library.map")}",
      )
      linkerOpts("-lace_napi.z", "-luv", "-lhilog_ndk.z")
    }
  }
}

链接器只导出三个 C ABI 符号:

WhatIfCatalog
WhatIfRunChecks
WhatIfFree

目录、检查和释放已经覆盖示例所需能力;减少 ABI 符号可以降低 Native 生命周期
和兼容风险。

2.3 配置独立 example 工程

example/settings.gradle.kts 使用 OpenHarmony 社区 Maven、Maven Central 和
Gradle Plugin Portal:

pluginManagement {
  repositories {
    maven("https://maven.eazytec-cloud.com/nexus/repository/maven-public/")
    mavenCentral()
    gradlePluginPortal()
  }
}

dependencyResolutionManagement {
  repositories {
    mavenLocal()
    maven("https://maven.eazytec-cloud.com/nexus/repository/maven-public/")
    mavenCentral()
  }
}

示例通过 composite substitution 消费当前仓库的 whatif 项目:

includeBuild("..") {
  dependencySubstitution {
    substitute(module("com.github.skydoves:whatif"))
      .using(project(":whatif"))
  }
}

共享模块仍然以正常坐标表达依赖:

sourceSets {
  commonMain.dependencies {
    api("com.github.skydoves:whatif:1.2.2")
  }
}
2.4 通过构建产物消费共享库

prepareOhos 在 Native 链接成功后复制动态库和 C 头文件:

val prepareOhos by tasks.registering(Copy::class) {
  dependsOn("linkDebugSharedOhosArm64")
  from(layout.buildDirectory.dir("bin/ohosArm64/debugShared")) {
    include("libwhatif.so")
    into("libs/arm64-v8a")
  }
  from(layout.buildDirectory.dir("bin/ohosArm64/debugShared")) {
    include("libwhatif_api.h")
    into("src/main/cpp/include")
  }
  into(rootProject.layout.projectDirectory.dir("ohosApp/entry"))
}

动态库、生成头文件和 HAP 属于构建产物,仓库通过 .gitignore 排除它们;每台
开发机都可以从源码重新生成与自身 SDK 匹配的文件。

第 3 阶段:行为与序列化

3.1 为什么需要统一 JSON 契约

Kotlin/Native 返回的是 Kotlin 侧的字符串指针,C++ N-API 再把它转换为 ArkTS
字符串。跨语言边界不传递 WhatIfExample 对象本身,而是使用稳定的 UTF-8 JSON:

WhatIfExamples.catalog()
        ↓ Kotlin data class -> JSON
WhatIfCatalog()
        ↓ const char* + WhatIfFree()
C++ N-API getCatalog()
        ↓ JavaScript string
WhatIfClient.ets -> JSON.parse()
        ↓
Index.ets 页面状态

这样页面只负责解析展示,条件判断、空值处理、集合处理和 Boolean 逻辑仍然只在
Kotlin commonMain 中维护。

3.2 WhatIfExamples facade

示例公共 facade 位于 example/shared/src/commonMain,将原库扩展函数组织为四个
可观察场景:

public object WhatIfExamples {
  public fun catalog(): List<WhatIfExample> = listOf(
    WhatIfExample("what-if", "条件执行", evaluateWhatIf()),
    WhatIfExample("what-if-map", "空值映射", evaluateMap()),
    WhatIfExample("collections", "集合扩展", evaluateCollections()),
    WhatIfExample("boolean", "布尔扩展", evaluateBoolean()),
  )
}

四个场景分别验证:whatIf(true) 执行 true 分支,whatIfMap 对空值返回默认值,
whatIfNotNullOrEmpty 覆盖 List、Array 和 String,以及 whatIfElse、
whatIfAnd、whatIfOr 的 Boolean 组合。

3.3 八项公共检查

runChecks() 返回固定顺序的检查名称,并在任意检查失败时抛出异常。当前八项检查
覆盖:

  1. whatIf 只执行 true 分支;
  2. whatIfMap 对 null 返回默认值;
  3. 可空集合、数组和字符串的非空判断;
  4. 可空 Boolean 的 whatIfElse;
  5. 可变集合按条件添加非空值;
  6. whatIfNotNull 执行非空分支;
  7. whatIfAnd 和 whatIfOr 保持谓词语义;
  8. 公共 facade 不包含平台类型。

返回给 ArkTS 的 JSON 形状如下:

{
  "passed": true,
  "checks": [
    "whatIf executes only for true",
    "whatIfMap returns the default for null"
  ]
}

checks.length 在页面上显示为 8/8 公共检查通过。检查名称使用英文是为了让
JVM、Native 和 ArkTS 日志都保持稳定,页面状态文字仍然使用中文。

3.4 JSON 字符串和错误边界

NativeBridge.kt 中的 quote 会转义反斜杠、双引号和控制字符;response 捕获
Kotlin 异常并返回 {"error":"..."}。这样 C++ 和 ArkTS 不需要解析 Kotlin
异常对象,也不会因为错误信息包含特殊字符而得到无效 JSON。

第 4 阶段:原生桥接(技术难点)

4.1 Kotlin/Native 对象不能直接交给 ArkTS

WhatIfExample 是 Kotlin data class,属于 Kotlin/Native 运行时对象。ArkTS 只能
接收 JavaScript 值,C++ 也不能把 Kotlin 对象地址当作 JavaScript 对象使用。本项目
采用三层桥接:

ArkTS
  │ JSON string
  ▼
C++ N-API entry
  │ const char*
  ▼
Kotlin/Native C ABI
  │ WhatIfExamples
  ▼
UTF-8 JSON + explicit free
4.2 方案对比
方案优点缺点选用
直接导出 Kotlin 对象代码少ABI、生命周期和类型不可控❌
只导出场景编号实现简单页面无法拿到共享扩展的真实结果❌
C ABI + JSON边界清晰、易扩展、易调试有一次序列化开销✅
在 ArkTS 重写 WhatIf 逻辑页面调用简单Kotlin 和 ArkTS 逻辑容易分叉❌
4.3 Kotlin/Native 导出函数
@CName("WhatIfCatalog")
public fun catalogNative(): CPointer<ByteVar> = response {
  WhatIfExamples.catalog().joinToString(prefix = "[", postfix = "]") { it.toJson() }
}

@CName("WhatIfRunChecks")
public fun checksNative(): CPointer<ByteVar> = response {
  val checks = WhatIfExamples.runChecks()
  "{\"passed\":true,\"checks\":[${checks.joinToString { quote(it) }}]}"
}

@CName("WhatIfFree")
public fun freeNative(pointer: CPointer<ByteVar>?) {
  if (pointer != null) nativeHeap.free(pointer.rawValue)
}

返回值由 nativeHeap 分配为以 0 结尾的 C 字符串。C++ 创建 ArkTS 字符串后立即
调用 WhatIfFree,每一块 Native 缓冲区都有明确的释放责任。

4.4 C++ N-API 方法分发

napi_init.cpp 注册两个供 ArkTS 使用的方法:

napi_property_descriptor methods[] = {
    {"getCatalog", nullptr, Catalog, nullptr, nullptr, nullptr,
        napi_default, nullptr},
    {"runChecks", nullptr, RunChecks, nullptr, nullptr, nullptr,
        napi_default, nullptr},
};

每个方法都遵循“调用 Kotlin/Native、创建 ArkTS 字符串、释放 Native 缓冲区”的
顺序。N-API 只做字符串转换和导出注册,不重新解释 WhatIf 的条件语义。

4.5 CMake 和 linker map

Kotlin/Native 动态库以 imported library 的方式交给 CMake:

add_library(whatif SHARED IMPORTED)
set_target_properties(whatif PROPERTIES
  IMPORTED_LOCATION "${CMAKE_CURRENT_SOURCE_DIR}/../../../libs/arm64-v8a/libwhatif.so")

add_library(entry SHARED napi_init.cpp)
target_include_directories(entry PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/include")
target_link_libraries(entry PRIVATE whatif libace_napi.z.so)

shared-library.map 限制导出符号为 WhatIfCatalog、WhatIfRunChecks 和
WhatIfFree。这让动态库的公开 ABI 保持最小,避免把 Kotlin/Native 内部符号泄漏
到 HAP。

第 5 阶段:ArkUI 宿主

5.1 WhatIfClient.ets

ArkTS 客户端只负责把 Native 返回的 JSON 解析成页面类型:

import whatIfNative from 'libentry.so';

export function catalog(): WhatIfExample[] {
  return JSON.parse(whatIfNative.getCatalog()) as WhatIfExample[];
}

export function runChecks(): WhatIfChecks {
  return JSON.parse(whatIfNative.runChecks()) as WhatIfChecks;
}
5.2 Index.ets 页面状态

页面在 aboutToAppear 中读取目录并运行公共检查;点击能力列表只切换当前记录,
不会把 WhatIf 扩展函数复制成 ArkTS 逻辑:

@State private examples: WhatIfExample[] = [];
@State private selected: WhatIfExample = emptyExample();
@State private status: string = '正在加载';

private refresh(): void {
  this.examples = catalog();
  this.selected = this.examples[0] ?? emptyExample();
  const checks = runChecks();
  this.status = checks.passed
    ? `${checks.checks.length}/8 公共检查通过`
    : '公共检查失败';
}

页面包括标题、Native READY 状态、当前场景、结果说明、四个能力入口、重新运行
检查按钮和底部数据来源说明。发生 Native 错误时,错误文本会出现在页面底部。

5.3 页面与真实能力的边界

当前示例展示的是 WhatIf 公共扩展执行结果,不声明设备传感器或系统动作能力。页面
选择场景和重新运行检查都经过 libentry.so,因此效果图能够说明 Kotlin/Native、
N-API 和 ArkTS 页面已经连通;它不替代签名安装后的真机行为验证。

第 6 阶段:示例与验证

6.1 example 工程结构
example/
├── shared/
│   ├── src/commonMain/.../WhatIfExamples.kt
│   └── src/commonTest/.../WhatIfExamplesTest.kt
├── nativeApp/
│   ├── src/ohosArm64Main/.../NativeBridge.kt
│   └── src/ohosArm64Main/linker/shared-library.map
└── ohosApp/
    ├── entry/src/main/cpp/
    │   ├── CMakeLists.txt
    │   └── napi_init.cpp
    └── entry/src/main/ets/
        ├── pages/Index.ets
        └── whatif/WhatIfClient.ets

shared 验证公共 facade,nativeApp 产生 ARM64 动态库,ohosApp 负责 CMake、
N-API 和 ArkUI 页面。三层可以分别构建,便于定位失败位置。

6.2 Native 模块注册

napi_init.cpp 通过 napi_module_register 注册 entry 模块,ArkTS 类型声明
位于:

example/ohosApp/entry/src/main/cpp/types/libentry/index.d.ts

ArkTS 通过下面的模块导入使用 Native 方法:

import whatIfNative from 'libentry.so';
6.3 Native 动态库准备

执行:

export JAVA_HOME="/path/to/jdk-21"
./scripts/build-openharmony.sh

脚本会运行根模块 JVM 测试、示例 JVM 测试、linkDebugSharedOhosArm64 和
prepareOhos。成功后会在本机构建出:

example/ohosApp/entry/libs/arm64-v8a/libwhatif.so
example/ohosApp/entry/src/main/cpp/include/libwhatif_api.h
6.4 构建、签名和安装

构建脚本当前明确生成未签名 HAP:

./scripts/build-hap.sh "$PWD/example/ohosApp"

脚本输出位置为:

example/ohosApp/entry/build/default/outputs/default/entry-default-unsigned.hap

签名配置需要在 DevEco Studio 或本机工程中完成后,才可以安装到设备。证书、profile、
P12 和密码不写入仓库;未完成签名时不执行安装命令。

四、完整代码对照

4.1 整体架构

WhatIf commonMain extensions
    │ whatIf / whatIfMap / collection / Boolean APIs
    ▼
WhatIfExamples.kt
    │ catalog() / runChecks()
    ▼
Kotlin/Native C ABI
    │ WhatIfCatalog / WhatIfRunChecks / WhatIfFree
    ▼
libwhatif.so + C++ N-API libentry.so
    │ UTF-8 JSON
    ▼
WhatIfClient.ets
    │ JSON.parse()
    ▼
Index.ets ArkUI page

4.2 文件清单

文件职责
whatif/src/commonMainWhatIf 原始条件、空值、集合和 Boolean 扩展
example/shared/src/commonMain/.../WhatIfExamples.kt场景 facade、JSON 记录来源和八项检查
example/shared/src/commonTestJVM 公共行为测试
example/nativeApp/src/ohosArm64Main/.../NativeBridge.ktC ABI、JSON 返回和内存释放
example/nativeApp/src/ohosArm64Main/linker/shared-library.mapNative 导出符号白名单
example/ohosApp/entry/src/main/cpp/napi_init.cppN-API 注册、字符串转换和释放
example/ohosApp/entry/src/main/cpp/CMakeLists.txt链接 libwhatif.so 和 libace_napi.z.so
example/ohosApp/entry/src/main/ets/whatif/WhatIfClient.etsN-API JSON 解析和类型定义
example/ohosApp/entry/src/main/ets/pages/Index.etsArkUI 页面和场景选择
scripts/build-openharmony.sh测试、Native 链接和产物复制
scripts/build-hap.shHvigor 未签名 HAP 构建
scripts/check-native-deps.pyARM64 ELF 强依赖检查
docs/openharmony/VALIDATION.md自动检查和签名边界说明

4.3 关键 API 对照

层次API作用
KotlinwhatIf条件成立时执行 true 分支
KotlinwhatIfMap根据空值安全返回映射或默认值
KotlinwhatIfNotNullOrEmpty处理集合、数组和字符串的非空分支
KotlinwhatIfElse / whatIfAnd / whatIfOr组合 Boolean 条件
Kotlin facadeWhatIfExamples.catalog返回四个示例场景
Kotlin facadeWhatIfExamples.runChecks执行八项公共检查
NativeWhatIfCatalog返回场景目录 JSON
NativeWhatIfRunChecks返回公共检查 JSON
NativeWhatIfFree释放 Native 字符串
ArkTScatalog / runChecks解析 N-API 返回值

4.4 ArkTS 与 Kotlin 的边界

ArkTS 只保存目录、当前选择和检查状态:

this.examples = catalog();
this.selected = this.examples[0] ?? emptyExample();
const checks = runChecks();
this.status = `${checks.checks.length}/8 公共检查通过`;

Kotlin 负责真正调用原库扩展:

private fun evaluateWhatIf(): String {
  var result = "false branch"
  "payload".whatIf(true) { result = "true branch" }
  return result
}

两者之间只传输 JSON 字符串,不传输 Kotlin 对象地址或未经约束的动态对象。

五、关键决策说明

决策 1:把 ohosArm64 加入公共构建约定

只有把 whatif 和示例 Native 模块都编译为 ohosArm64,才能确认原始
commonMain 扩展在 OpenHarmony ARM64 工具链上可编译和可链接。

决策 2:独立消费者通过构建产物消费

example 作为独立 Gradle 工程解析根项目,ohosApp 只接收生成的 .so 和头文件。
这样 Gradle 测试、Native 链接和 Hvigor 打包的边界清楚,根工程构建成功也不会掩盖
DevEco 工程缺少 Native 产物的问题。

决策 3:JSON 作为跨语言数据契约

目录和检查结果字段少且稳定,JSON 便于 ArkTS 调试,也避免暴露 Kotlin/Native 对象
布局。后续增加展示字段时可以保持已有字段兼容。

决策 4:只开放三个 C ABI 入口

目录、检查和释放已经覆盖当前示例;不额外导出内部扩展函数,减少 Native ABI 和
生命周期风险。

决策 5:页面选择与检查执行分开

页面切换能力入口只改变当前展示记录;公共检查通过 Native 重新执行。这样可以同时
验证“读取共享结果”和“重复执行共享逻辑”两条路径。

决策 6:库验证与设备验证分开

JVM 测试验证公共语义,Native 链接验证 ABI,ELF 检查验证系统依赖,Hvigor 验证 HAP
工程。当前尚未配置签名和安装设备,因此文章不把未签名 HAP 当作真机验收结论。

六、测试与验证

6.1 测试环境

本次验证使用 macOS、JDK 21、Kotlin Multiplatform 2.2.21-1.0.0、DevEco Studio
6.0.0(20) 和 OpenHarmony ARM64 Native SDK。签名证书和设备安装不属于本次已完成的
验证范围。

6.2 静态检查与单元测试

已执行:

./gradlew :whatif:jvmTest
(cd example && ./gradlew :shared:jvmTest)

根模块和示例模块的 JVM 测试通过,示例检查覆盖条件执行、空值映射、集合/数组/字符串、
Boolean、可变集合、非空接收者和逻辑谓词。

6.3 原生桥接和 HAP 验证

已执行:

./scripts/build-openharmony.sh
./scripts/build-hap.sh "$PWD/example/ohosApp"

Native 依赖检查结果为:

libc++_shared.so: 0 unresolved strong imports
libentry.so: 0 unresolved strong imports
libwhatif.so: 0 unresolved strong imports

HAP 构建产物为:

example/ohosApp/entry/build/default/outputs/default/entry-default-unsigned.hap

Hvigor 构建成功,但当前工程没有可用的签名配置,日志提示 No signingConfig found for product default。因此没有执行签名、安装或设备功能验证,也没有把任何证书、密钥
或密码提交到 AtomGit。

6.4 已完成的验证用例

用例 1:共享模块行为

JVM 测试直接调用 WhatIfExamples.runChecks(),确认八项公共检查全部通过。

用例 2:Native 动态库

linkDebugSharedOhosArm64 成功生成 libwhatif.so 和 C 头文件,C++ N-API 模块成功
链接到该动态库。

用例 3:ArkUI 页面构建

Hvigor 成功编译并打包 ohosApp,页面所需的 libentry.so 和 libwhatif.so 已进入
ARM64 构建链路。

用例 4:效果图对应的页面内容

效果图展示了 WhatIf 工作台、四个能力入口、true branch、8/8 公共检查通过 和
Kotlin/Native → N-API → ArkTS 说明。这些内容来自页面数据和构建结果;它不证明签名
HAP 已经在设备上安装。

6.5 验证结论

当前可以确认:共享 Kotlin API 的 JVM 测试通过,OpenHarmony ARM64 Native 动态库
成功链接,C++ N-API 模块和 ArkUI HAP 成功构建,Native 强依赖检查通过。签名和真机
安装需要在本机配置证书后继续完成。

七、运行效果

7.1 WhatIf 工作台效果图

在这里插入图片描述

图中可以看到:

  • 页面标题为“WhatIf 工作台”;
  • 副标题为“Kotlin Multiplatform / OpenHarmony”;
  • 当前条件执行结果显示 true branch;
  • 页面提供条件执行、空值映射、集合扩展和布尔扩展四个入口;
  • 底部显示 8/8 公共检查通过;
  • 页面明确标注 Kotlin/Native → N-API → ArkTS 的数据路径。

7.2 命令速查

# 根工程和 example JVM 测试、Native 动态库准备
export JAVA_HOME="/path/to/jdk-21"
./scripts/build-openharmony.sh

# 单独运行示例共享测试
(cd example && ./gradlew :shared:jvmTest)

# 检查打包的 ARM64 Native 库强依赖
python3 scripts/check-native-deps.py \
  /Applications/DevEco-Studio.app/Contents/sdk/default/openharmony/native \
  example/ohosApp/entry/libs/arm64-v8a

# 构建未签名 HAP
./scripts/build-hap.sh example/ohosApp

配置签名后,再由开发者在 DevEco Studio 或本机 HAP 工程中完成签名和设备安装。

八、遗留问题与改进方向

8.1 踩坑复盘

  1. 只改 ArkTS 页面不算 KMP 适配:必须把原始 commonMain 真正编译为
    ohosArm64 动态库并由页面调用。
  2. N-API 不负责业务判断:C++ 只完成模块注册、字符串转换和释放,WhatIf 语义
    放在 Kotlin 公共代码。
  3. Native 字符串必须释放:每次 WhatIfCatalog 或 WhatIfRunChecks 返回的
    缓冲区都要调用 WhatIfFree。
  4. JDK 版本需要固定:当前 Kotlin/Gradle 组合按 JDK 21 验证,其他版本要重新确认。
  5. 签名和构建分开:Hvigor 能成功生成未签名 HAP,不等于可以安装到设备。

8.2 已知问题

  • 当前示例只接受 ARM64 OpenHarmony 目标,未提供其他 ABI 的 Native 产物;
  • 当前仓库验证了 Native 和 HAP 构建,尚未发布独立 HAR/npm 交付包;
  • HAP 当前为未签名产物,未执行设备安装和真实设备交互验收;
  • 页面使用 JSON.parse 读取固定契约,正式产品可增加字段版本和错误类型;
  • WhatIf 扩展本身是无状态函数,后续示例可加入 Compose Multiplatform 页面以展示
    同一公共 facade 的更多 UI 宿主。

8.3 未来优化方向

  • 发布可直接消费的 OpenHarmony Native/HAR 产物,并补充版本化交付说明;
  • 为 Compose Multiplatform 增加与 ArkUI 页面一致的场景卡片;
  • 在 CI 中固定 JDK、Native SDK 和 HAP 未签名构建检查;
  • 增加 JSON 契约测试、错误码和 API 版本字段;
  • 在具备签名和设备条件后,补做安装、启动、页面交互和 Native 依赖回归。

九、总结

9.1 核心难点回顾

WhatIf 的鸿蒙适配不是把 Kotlin 条件判断翻译成 ArkTS,而是让同一份共享代码
经过完整链路进入 OpenHarmony:

WhatIf commonMain
    → ohosArm64 Kotlin/Native
    → C ABI JSON
    → C++ N-API
    → ArkTS JSON.parse
    → ArkUI 工作台

9.2 封装层次

  • KMP 层:保留条件、空值、集合和 Boolean 扩展的公共语义;
  • 示例 facade:把扩展函数组织成四个场景并提供八项检查;
  • Native 层:生成 ARM64 动态库,只导出三个 C ABI 入口;
  • N-API 层:完成模块注册、字符串转换和 Native 缓冲区释放;
  • ArkTS 层:解析 JSON、管理页面状态并展示验证结果;
  • DevEco 层:完成 CMake、Hvigor、HAP 构建和后续签名入口。

9.3 三条经验

  1. 先让公共 API 在 JVM 和 Native 目标通过,再接入 ArkUI 页面;
  2. 用 JSON 和少量 C ABI 代替跨语言对象传递,并让释放责任回到导出方;
  3. 分开记录测试、Native 链接、依赖检查、HAP 构建和设备验证,避免把构建成功写成
    真机验收完成。

9.4 适配成果

当前 WhatIf OpenHarmony 适配已完成:

  • whatif 公共模块加入 ohosArm64 目标;
  • WhatIfExamples 覆盖四个典型 WhatIf 使用场景;
  • JVM 和 Native 共用八项公共检查;
  • Kotlin/Native + C ABI + C++ N-API + ArkTS JSON 链路打通;
  • ARM64 Native 依赖检查通过;
  • ArkUI WhatIf 工作台和效果图已加入仓库;
  • HAP 未签名构建成功,签名材料保留给开发者本机配置;
  • 项目说明、文章和源码链接统一使用 AtomGit。

参考文档

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐