本文记录 Ksoup 适配 OpenHarmony 的完整过程:从 Kotlin Multiplatform 目标配置、OpenHarmony Kotlin/Native 工具链对齐,到独立消费工程、Kotlin/Native 动态库、C++ N-API 桥接、ArkTS 交互页面和签名 HAP 验收。

这次适配的目标是让 Ksoup 原有的 HTML 解析、标签与属性回调、文本提取、注释解析以及 HTML 实体编解码能力继续复用,同时为 OpenHarmony ARM64 提供一个可以真实输入和操作的示例页面。页面不会只显示“测试通过”,而是可以输入 HTML、查看解析结构,输入实体文本、查看编码和解码结果,再通过库自检工作区确认 Native 桥接和共享 API 正常。

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

开发工具: 华为云码道


一、项目背景

1.1 Ksoup 是什么

Ksoup 是一个轻量级 Kotlin Multiplatform HTML 工具库,当前仓库包含两个核心模块:

  • ksoup-html:流式 HTML 解析器,以及标签、属性、文本和注释回调。
  • ksoup-entities:HTML5、HTML4 和 XML 实体的编码与解码。

公共实现位于 commonMain。解析器可以通过 KsoupHtmlParser 配合 KsoupHtmlHandler 处理完整字符串,也可以使用 writeend 进行分块输入。实体模块通过 KsoupEntities.encodeHtmlKsoupEntities.decodeHtml 提供编解码能力。

这两个模块本身不依赖平台 UI。OpenHarmony 适配的重点是让相同的公共 API 生成可被 OpenHarmony ARM64 应用加载的 Kotlin/Native 动态库,并在 ArkTS 页面中验证真实调用链。

1.2 为什么需要 OpenHarmony 目标

JVM 或其他 Kotlin/Native 产物不能直接作为 OpenHarmony 应用的原生库。要让 ArkTS 页面使用 Ksoup 的公共解析逻辑,需要解决以下问题:

障碍具体问题
目标缺失原工程没有 ohosArm64(),无法产生 OpenHarmony ARM64 KLIB。
工具链不一致Kotlin/Native 编译器、OpenHarmony sysroot 和 Kotlin Multiplatform 插件必须匹配。
构建范围过大同时配置所有平台会下载大量与 OpenHarmony 验收无关的工具链。
消费方式不同只编译根工程不能证明独立消费者能解析 Maven metadata、KLIB 和版本坐标。
应用边界不同Kotlin/Native API 需要通过稳定的 C ABI 和 C++ N-API 进入 ArkTS。
验收形式不同编译通过不能说明用户真的能输入 HTML 并看到解析结果。

适配原则是保留 commonMain 的解析和实体算法,把平台差异收敛到目标配置、独立消费工程、Native 桥接和应用打包层。

1.3 适配后提供的能力

完成适配后,仓库提供:

  • ksoup-htmlksoup-entitiesohosArm64 Kotlin/Native 目标。
  • -PopenharmonyOnly=true focused build,减少本地开发时的无关目标配置。
  • 独立的 example/ 消费工程,通过 mavenLocal() 使用已发布的 Ksoup 坐标。
  • shared 模块中的 JVM 与 OHOS 共享验收逻辑。
  • nativeApp 模块生成 libksoup.so,导出解析、实体和自检的 C ABI。
  • C++ N-API 模块,把 ArkTS 字符串传给 Kotlin/Native,再把 JSON 结果返回给 ArkTS。
  • ArkTS 交互式页面,包含 HTML 解析器、实体工具和库自检三个工作区。
  • 构建、签名工程准备、HAP 构建和 ARM64 ELF 依赖检查脚本。

1.4 版本矩阵

组件版本或要求
Ksoup 适配版本0.6.0-ohos.1
Maven 坐标com.mohamedrejeb.ksoup:ksoup-html:0.6.0-ohos.1com.mohamedrejeb.ksoup:ksoup-entities:0.6.0-ohos.1
Kotlin Gradle plugin / Native2.2.21-1.0.0
OpenHarmony targetohosArm64
应用 ABIarm64-v8a
HarmonyOS target / compatible API6.0.0(20)
Gradle8.14.3
JDK21
DevEco Studio6 或更高版本

ohosArm64 是 Kotlin/Native 目标名称,arm64-v8a 是 DevEco/HAP 使用的 ABI 名称,两者需要同时配置。

二、整体实现路线

本次适配分为六个阶段:

第 1 阶段:盘点工程边界     ── 确认 commonMain、解析器 API 和实体 API
第 2 阶段:增加 OHOS 目标    ── 加入 ohosArm64 和 focused build
第 3 阶段:独立消费验证      ── 通过 Maven 坐标构建 shared 模块
第 4 阶段:Native 桥接        ── Kotlin/Native 动态库、C ABI、C++ N-API
第 5 阶段:交互页面          ── ArkTS 输入 HTML 和实体并展示结果
第 6 阶段:构建和验收         ── JVM、OHOS、HAP、ELF 和设备分层验证

最终依赖方向如下:

ohosApp → nativeApp → shared → ksoup-html + ksoup-entities

shared 通过发布坐标消费库,nativeApp 依赖 shared 并生成动态库,ohosApp 通过 C++ N-API 加载动态库。

三、根工程增加 OpenHarmony 目标

3.1 配置仓库和版本

OpenHarmony Kotlin/Native 发行包来自社区 Maven 仓库,因此插件仓库和依赖仓库都要加入该地址:

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

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

gradle.properties 固定 Kotlin/Native 从 Maven 下载,并声明适配版本:

kotlin.native.ignoreDisabledTargets=true
kotlin.mpp.stability.nowarn=true
kotlin.native.distribution.downloadFromMaven=true
kotlin.native.enableKlibsCrossCompilation=true

version=0.6.0-ohos.1

发布插件中的项目地址、问题入口和 SCM 地址统一使用 AtomGit:

pom {
    url.set("https://atomgit.com/oh-tpc/ohos_Ksoup")
    scm {
        url.set("https://atomgit.com/oh-tpc/ohos_Ksoup")
        connection.set("scm:git:https://atomgit.com/oh-tpc/ohos_Ksoup.git")
    }
}

3.2 声明 ohosArm64

ksoup-htmlksoup-entities 都在原有目标之外增加 ohosArm64()

kotlin {
    applyDefaultHierarchyTemplate()
    explicitApi()
    ohosArm64()

    jvm {
        compilations.configureEach {
            compileTaskProvider.configure {
                compilerOptions {
                    jvmTarget = JvmTarget.JVM_1_8
                }
            }
        }
    }

    if (!providers.gradleProperty("openharmonyOnly")
            .map(String::toBoolean)
            .getOrElse(false)) {
        androidNativeArm32()
        androidNativeArm64()
        js(IR).nodejs()
        iosArm64()
        linuxX64()
        macosArm64()
        // 其他原有平台目标
    }
}

openharmonyOnly 只改变目标配置范围,不改变公共源码:

./gradlew -PopenharmonyOnly=true tasks

focused build 中保留 JVM 和 OpenHarmony,跳过 JS、Wasm 以及其他不相关 Native 工具链,可以明显减少首次配置和迭代时间。

3.3 为什么不能只改示例

如果只在 example/nativeApp 中声明 ohosArm64(),示例可能拥有一个 Native 目标,但根库不会产生可消费的 OpenHarmony KLIB。正确关系是:

ksoup-html / ksoup-entities commonMain
        ├─ JVM publication
        ├─ Kotlin Multiplatform metadata
        └─ OHOS ARM64 publication
                       │
                       ▼
example/shared 通过 Maven 坐标解析

因此 ohosArm64() 必须出现在库模块的 KMP 配置中,示例工程再单独声明自己的目标。

四、独立消费工程

4.1 为什么新增独立 example/

根工程里的单元测试只能证明当前源码能运行,不能证明外部消费者能正确解析:

  • Kotlin Multiplatform metadata。
  • ksoup-htmlksoup-entities 的 JVM artifact。
  • OpenHarmony ARM64 artifact。
  • 版本号、POM 和 mavenLocal() 中的发布坐标。

因此示例工程不直接依赖根工程项目,而是使用真实坐标:

kotlin {
    jvm()
    jvmToolchain(21)
    ohosArm64()

    sourceSets {
        commonMain.dependencies {
            implementation("com.mohamedrejeb.ksoup:ksoup-html:0.6.0-ohos.1")
            implementation("com.mohamedrejeb.ksoup:ksoup-entities:0.6.0-ohos.1")
        }
        commonTest.dependencies {
            implementation(kotlin("test"))
        }
    }
}

使用前先发布本地 Maven 产物:

./gradlew -PopenharmonyOnly=true \
  -PsignPublications=false \
  :ksoup-entities:publishToMavenLocal \
  :ksoup-html:publishToMavenLocal

4.2 示例工程目录

example/
  shared/
    build.gradle.kts
    src/commonMain/kotlin/.../AcceptanceChecks.kt
    src/commonTest/kotlin/.../AcceptanceChecksTest.kt
  nativeApp/
    build.gradle.kts
    src/ohosArm64Main/kotlin/.../NativeChecks.kt
    src/ohosArm64Main/linker/shared-library.map
  ohosApp/
    AppScope/
    entry/
      src/main/ets/pages/Index.ets
      src/main/cpp/napi_init.cpp
      src/main/cpp/CMakeLists.txt

4.3 共享验收场景

shared 直接调用发布坐标中的 Ksoup API,当前覆盖:

  1. HTML5 实体编码。
  2. HTML5 实体解码。
  3. 标签和文本解析。
  4. 属性解析。
  5. 注释解析。
  6. 分块输入解析。
  7. 两个文档的独立解析。
  8. 重复标签属性保留。

共享测试保持最小边界:

@Test
fun allChecksPass() {
    val checks = runAcceptanceChecks()
    assertTrue(checks.isNotEmpty())
    assertTrue(checks.all { it.passed })
}

测试通过只能说明共享逻辑正确,后续还要继续经过 OHOS 编译、Native 链接和 HAP 构建。

五、把 Ksoup 能力做成真实交互页面

5.1 页面不只显示 PASS

如果验收页只显示检查列表,使用者无法感知 HTML 解析器和实体库的实际行为。当前页面拆分为三个工作区:

  • HTML 解析器:输入一段 HTML,查看标签序列、文本内容、每个标签的属性和注释。
  • 实体工具:输入普通文本或已有实体,同时查看 encodeHtmldecodeHtml 结果。
  • 库自检:调用 Kotlin/Native 中的共享验收逻辑,确认实体、解析器、分块输入和重复属性场景均通过。

默认 HTML 示例为:

<article data-kind="demo">
  <h1>Ksoup</h1>
  <!--native-->
  <p>Hello &amp; 鸿蒙</p>
</article>

菜单示例可以观察重复属性是否被完整保留:

<ul class="menu">
  <li data-id="1">首页</li>
  <li data-id="2">设置</li>
</ul>
<!-- rendered by Ksoup -->

页面会显示 ul › li › li首页设置,并分别列出 ulclass 与两个 lidata-id

5.2 Kotlin 共享解析模型

共享模块把 Ksoup 回调组合为页面需要的模型:

public data class ParsedHtml(
    val tags: List<String>,
    val text: String,
    val comments: List<String>,
    val attributes: Map<String, String>,
    val attributeEntries: List<HtmlAttribute> = emptyList(),
)

public data class HtmlAttribute(
    val tag: String,
    val tagIndex: Int,
    val name: String,
    val value: String,
)

public fun parseHtml(input: String): ParsedHtml {
    val tags = mutableListOf<String>()
    val comments = mutableListOf<String>()
    val text = StringBuilder()
    val attributes = linkedMapOf<String, String>()
    val attributeEntries = mutableListOf<HtmlAttribute>()

    val handler = KsoupHtmlHandler.Builder()
        .onOpenTag { name, values, _ ->
            tags += name
            values.forEach { (key, value) ->
                attributes[key] = value
                attributeEntries += HtmlAttribute(name, tags.size, key, value)
            }
        }
        .onText { value -> text.append(value) }
        .onComment { value -> comments += value }
        .build()

    KsoupHtmlParser(handler = handler).parseComplete(input)
    return ParsedHtml(tags, text.toString(), comments, attributes, attributeEntries)
}

解析器和实体模块仍然来自 Ksoup 本身,shared 只负责把回调整理成可序列化的结果。

5.3 实体编解码操作

实体工具调用共享函数:

public data class EntityReport(
    val encoded: String,
    val decoded: String,
)

public fun transformEntities(input: String): EntityReport = EntityReport(
    encoded = KsoupEntities.encodeHtml(input),
    decoded = KsoupEntities.decodeHtml(input),
)

例如输入 Tom & Jerry <3,页面会显示:

encodeHtml: Tom &amp; Jerry &lt;3
decodeHtml: Tom & Jerry <3

输入 &#128512; &amp; 中文 时,解码结果会显示 😀 & 中文,可以直接观察 Unicode 数字实体和命名实体的处理。

5.4 ArkTS 页面状态和结果刷新

ArkTS 页面通过 N-API 导出的函数调用 Native:

private runParser(input: string = this.htmlInput): void {
  try {
    const result = JSON.parse(compare(input, '')) as ComparisonResult;
    this.parsed = result.source;
    this.errorMessage = '';
  } catch (error) {
    this.parsed = undefined;
    this.errorMessage = String(error);
  }
}

private runEntities(input: string = this.entityInput): void {
  try {
    this.entityReport = JSON.parse(entities(input)) as EntityReport;
    this.entityError = '';
  } catch (error) {
    this.entityReport = undefined;
    this.entityError = String(error);
  }
}

示例按钮使用局部输入值直接调用解析函数,避免在同一个状态更新事务中读取旧的 @State 值。结果区域使用带 @PropMetricCardResultCard 组件,确保输入变化后卡片内容同步刷新。

5.5 交互效果图

下面是签名应用在 OpenHarmony 手机上的实际页面效果。页面已经切换到菜单示例,解析结果显示标签序列、文本内容和每个标签的属性:

在这里插入图片描述

图中可以看到:

  • 顶部可以切换解析器、实体工具和库自检工作区。
  • HTML 输入框支持多行内容。
  • “运行解析”调用 Kotlin/Native 中的 Ksoup HTML parser。
  • “加载菜单示例”填充重复标签和重复属性场景。
  • 结果区显示 ul › li › li首页设置 和各标签属性。

六、Kotlin/Native 到 ArkTS 的桥接

6.1 调用链

ArkTS Index.ets
    │ compare(source, target) / entities(input) / runChecks()
    ▼
C++ N-API module (libentry.so)
    │ KsoupSampleCompare / KsoupSampleEntities / KsoupSampleRunChecks
    ▼
Kotlin/Native libksoup.so
    │ parseHtml / transformEntities / runAcceptanceChecks
    ├─ KsoupHtmlParser + KsoupHtmlHandler
    ├─ KsoupEntities.encodeHtml / decodeHtml
    └─ JSON string + KsoupSampleFree()
    ▼
ArkTS JSON.parse -> 页面状态 -> 结果卡片

库本身不直接暴露 ArkTS 类型。示例 Native 模块提供稳定的 C ABI,避免把 Kotlin 对象布局和生命周期泄漏到 C++。

6.2 Kotlin/Native 导出入口

nativeApp 使用 @CName 导出字符串接口:

@CName("KsoupSampleCompare")
public fun compareNative(source: String, target: String): CPointer<ByteVar> = try {
    textBuffer(comparisonJson(compareHtml(source, target)))
} catch (error: Throwable) {
    textBuffer("{\"error\":${quote(error.message ?: error.toString())}}")
}

@CName("KsoupSampleEntities")
public fun entitiesNative(input: String): CPointer<ByteVar> = try {
    textBuffer(entityJson(transformEntities(input)))
} catch (error: Throwable) {
    textBuffer("{\"error\":${quote(error.message ?: error.toString())}}")
}

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

返回值统一是 UTF-8 JSON 字符串。C++ 复制完成后调用 KsoupSampleFree 释放 Kotlin/Native 堆内存。

6.3 C++ N-API 参数转换

C++ 从 ArkTS 回调中读取字符串,调用 Native 导出函数,再把 JSON 转换成 ArkTS 字符串:

static napi_value Entities(napi_env env, napi_callback_info info) {
    size_t argc = 1;
    napi_value args[1] = {nullptr};
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);

    std::string input;
    if (!ReadString(env, args[0], input)) {
        napi_throw_type_error(env, nullptr, "entities argument must be a string");
        return nullptr;
    }

    auto text = KsoupSampleEntities(input.c_str());
    napi_value result = nullptr;
    const auto status = napi_create_string_utf8(
        env, reinterpret_cast<const char*>(text), NAPI_AUTO_LENGTH, &result);
    KsoupSampleFree(text);
    return status == napi_ok ? result : nullptr;
}

接口注册数量必须和描述数组一致:

napi_property_descriptor methods[] = {
    {"runChecks", nullptr, RunChecks, nullptr, nullptr, nullptr, napi_default, nullptr},
    {"compare", nullptr, Compare, nullptr, nullptr, nullptr, napi_default, nullptr},
    {"entities", nullptr, Entities, nullptr, nullptr, nullptr, napi_default, nullptr},
};
napi_define_properties(env, exports, sizeof(methods) / sizeof(methods[0]), methods);

如果注册数量少于实际数组长度,ArkTS 可能能加载部分函数,但会在导入 entities 时出现模块没有导出该名称的运行时错误。

6.4 动态库导出表

shared-library.map 只导出需要被 C++ 调用的入口:

{
    global:
        KsoupSampleCompare;
        KsoupSampleEntities;
        KsoupSampleRunChecks;
        KsoupSampleFree;
    local: *;
};

这样可以避免导出无关符号,也让 CMake 链接阶段明确找到交互入口。

七、构建和签名

7.1 一键构建

使用 JDK 21 执行:

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

脚本依次完成:

  1. ksoup-htmlksoup-entities 发布到 mavenLocal()
  2. 两个库的 JVM 测试。
  3. 两个库的 ohosArm64 编译。
  4. 独立 shared:jvmTest
  5. nativeApp:prepareOhos,生成并复制 libksoup.so 和头文件。

也可以分步执行:

./gradlew -PopenharmonyOnly=true \
  :ksoup-entities:jvmTest \
  :ksoup-html:jvmTest \
  :ksoup-entities:compileKotlinOhosArm64 \
  :ksoup-html:compileKotlinOhosArm64

(cd example && ./gradlew -PopenharmonyOnly=true \
  :shared:jvmTest :nativeApp:prepareOhos)

主要产物位置:

ksoup-entities/build/classes/kotlin/ohosArm64/main/klib/
ksoup-html/build/classes/kotlin/ohosArm64/main/klib/
example/ohosApp/entry/libs/arm64-v8a/libksoup.so
example/ohosApp/entry/src/main/cpp/include/libksoup_api.h

动态库、生成头文件和 HAP 构建产物由 .gitignore 排除,不进入源码提交。

7.2 准备 DevEco 工程

DevEco 对包含特殊字符或非 ASCII 字符的目录路径比较敏感。可以把应用复制到独立的签名目录:

python3 scripts/prepare-signing-project.py \
  "$HOME/ksoup_openharmony_signing"

脚本会复制 ArkTS、C++、资源和配置,排除构建缓存、OHPM 模块、CMake 临时目录和证书文件。如果目标目录已经有 build-profile.json5,脚本会保留目标目录中的签名配置。

7.3 构建 HAP

DEVECO_HOME="/Applications/DevEco-Studio.app/Contents" \
DEVECO_SDK_HOME="/Applications/DevEco-Studio.app/Contents/sdk" \
./scripts/build-hap.sh "$HOME/ksoup_openharmony_signing"

脚本执行 ohpm install --allhvigorw ... assembleHap。未配置签名时可以完成编译和打包流程,设备安装则需要在 DevEco 中配置有效证书和 profile。

签名材料只保留在本地开发环境,不应写入仓库或文章。

7.4 ELF 依赖审计

对解压后的 HAP 原生库检查架构和强符号:

python3 scripts/check-native-deps.py \
  /path/to/sdk/20/native \
  /path/to/extracted-hap/libs/arm64-v8a

该脚本检查:

  • 产物是否为 AArch64 ELF。
  • OpenHarmony SDK sysroot 和应用动态库是否提供所需符号。
  • 是否存在未解析的强依赖。

这是静态检查,不能替代签名后的真机运行。

八、验证结果

8.1 已完成的自动化验证

检查结果
ksoup-entities JVM 测试通过
ksoup-html JVM 测试通过
根库 compileKotlinOhosArm64通过
独立示例 shared:jvmTest通过
nativeApp:prepareOhos通过
CMake / Ninja 原生桥接编译通过
ArkTS 编译通过
签名 HAP 构建通过
Native 依赖检查0 unresolved strong imports

Native 自检覆盖实体编码、实体解码、标签文本、属性、注释、分块输入、重复标签属性和双文档解析,共 8 项。测试结果中的“通过”只代表对应层级已经通过:JVM 测试不能替代 OHOS 编译,OHOS 编译也不能替代设备安装。

8.2 真机验收步骤

  1. 运行 scripts/build-openharmony.sh
  2. 使用 prepare-signing-project.py 复制签名工程。
  3. 在 DevEco Studio 中配置 API 20 ARM64 签名。
  4. 构建并安装签名 HAP。
  5. 在解析器工作区点击“加载菜单示例”,确认标签、文本、注释和各标签属性更新。
  6. 在实体工具工作区点击“加载实体示例”,确认编码和解码结果同步变化。
  7. 手动输入 &#128512; &amp; 中文,点击“转换实体”,确认显示 😀 & 中文
  8. 切换到库自检,确认所有检查通过,再切换后台和恢复前台。

当前仓库不提交设备证书、私钥、密码或签名产物。真机结果应由实际设备和签名环境记录。

九、关键文件

文件作用
build.gradle.kts根工程仓库和插件配置。
settings.gradle.ktsAtomGit 适配所需的插件与依赖仓库配置。
ksoup-html/build.gradle.ktsHTML 模块的 KMP 目标和 OHOS 配置。
ksoup-entities/build.gradle.kts实体模块的 KMP 目标和 OHOS 配置。
example/shared/.../AcceptanceChecks.kt共享解析、实体和回归验收逻辑。
example/nativeApp/.../NativeChecks.ktKotlin/Native C ABI 入口和 JSON 序列化。
example/nativeApp/.../shared-library.map动态库导出符号控制。
example/ohosApp/entry/src/main/cpp/napi_init.cppC++ N-API 参数读取和 Native 调用。
example/ohosApp/entry/src/main/ets/pages/Index.etsHTML 解析、实体工具和库自检页面。
scripts/build-openharmony.sh发布、测试、OHOS 编译和 Native 库准备。
scripts/prepare-signing-project.py复制 DevEco 签名工程。
scripts/build-hap.shOHPM 安装和 HAP 构建。
scripts/check-native-deps.pyARM64 ELF 和符号依赖检查。
docs/images/ksoup-openharmony-demo.jpgOpenHarmony 交互页面效果图。

十、适配中的关键经验

10.1 目标配置要放在库构建层

只在示例中声明 ohosArm64,无法生成真正可消费的 Ksoup OpenHarmony 产物。目标必须和 ksoup-htmlksoup-entities 的 KMP 配置一起定义,示例再以发布坐标接入。

10.2 用 focused build 控制工具链下载

OpenHarmony 适配需要额外的 Native 编译器、LLVM 和 sysroot。openharmonyOnly 让开发者只配置 JVM/OHOS,普通构建则保留 Ksoup 原有平台矩阵。

10.3 交互验证比单纯 PASS 更有说服力

自检列表适合发现回归,但不能表现用户如何使用 HTML parser 和实体库。交互页面把输入、Native 调用和结果输出串在一起,可以直接观察标签序列、文本、注释、重复属性以及实体转换。

10.4 C ABI 只传字符串

通过 JSON 字符串传输结果,可以把 Kotlin 对象、集合和 Native 内存生命周期留在 Kotlin/Native 内部。C++ 和 ArkTS 只处理 UTF-8 字符串,桥接边界更稳定。

10.5 ArkTS 组件要显式接收动态值

页面结果卡片使用带 @Prop 的组件接收动态值,避免普通 @Builder 的参数在重渲染时保留首次显示内容。示例按钮也把新输入作为参数传入解析函数,避免同一状态事务中的旧值问题。

10.6 构建、打包和真机分层

应分别记录 JVM、KLIB、动态库、CMake、ArkTS、HAP 和设备结果。一个层级通过不能自动推出下一个层级通过。

10.7 AtomGit 地址必须全链路一致

源码文档、POM SCM、问题反馈入口和 Git remote 全部使用:

https://atomgit.com/oh-tpc/ohos_Ksoup

克隆和更新远端:

git clone https://atomgit.com/oh-tpc/ohos_Ksoup.git
cd ohos_Ksoup
git remote -v

十一、总结

本次适配没有复制一套鸿蒙专用 HTML 算法,而是保留 Ksoup 的 commonMain 实现,在库构建层增加 ohosArm64,在示例层增加真实消费和原生桥接,在应用层提供可操作的 HTML 解析和实体工具页面。

最终链路如下:

Ksoup commonMain API
        │
        ▼
Kotlin/Native ohosArm64
        │ libksoup.so
        ▼
C++ N-API
        │ JSON
        ▼
ArkTS interactive page
        │
        ├─ 输入 HTML,查看标签、文本、属性和注释
        ├─ 输入实体,查看 encodeHtml / decodeHtml
        ├─ 显示重复标签的属性明细
        └─ 运行 8 项 Native 验收

适配完成后,OpenHarmony 使用者可以像其他 KMP 消费者一样通过 Maven 坐标接入 Ksoup,也可以直接打开示例页面操作真实的 HTML 解析和实体编解码功能。项目地址为 AtomGit/oh-tpc/ohos_Ksoup


参考文档

环境: Kotlin 2.2.21-1.0.0 · HarmonyOS API 20 · Gradle 8.14.3 · JDK 21 · OpenHarmony ohosArm64

Logo

一站式 AI 云服务平台

更多推荐