KMP / CMP HarmonyOS 版本 Beta 發布,它有什麼特別之處?

華為官方適配的 KMP/CMP HarmonyOS 適配版本終於出來了,這個版本真的拖了好久了,雖然之前也有騰訊維護的 ovComposeKuikly 版本,但是現在華為官方的社群版本終於出來,也算是給了 KMP/CMP HarmonyOS 官方適配的名分

當然,它實際上和 ovComposeKuikly 版本也是密不可分。

事實上 KMP/CMP 適配 HarmonyOS 的門檻還是相當高的,它需要把 HarmonyOS 當作 Kotlin/Native 的新 Target 來實作,這次的實作路線需要大量的 KN 和 LLVM 適配,然後 Kotlin 會直接編譯成 HarmonyOS ELF 二進位,再用 NAPI / CAPI 和 ArkTS / ArkUI 協作完成渲染。

Kotlin/Native 用 KonanTarget 描述「我要為誰輸出二進位」,每個 Target 一般有三要素:family、architecture、triple。

當然,這套 Kotlin/Native 核心實作來自騰訊 KuiklyBase 體系,CMP UI 那邊的統一渲染也是來自騰訊 ovCompose,所以專案裡你可以看到不少 // region Tencent Cod 這樣的程式碼,grep "// region Tencent Code" -r 就能列出對應修改。

KMP HarmonyOS

KMP 適配 HarmonyOS,首先就是需要在 KonanTarget.kt 新增 OHOS 平台,同時擴充出 Family.OHOS

  • OHOS_ARM64 : KonanTarget("ohos_arm64", Family.OHOS, Architecture.ARM64)
  • OHOS_X64 : KonanTarget("ohos_x64", Family.OHOS, Architecture.X64)

這兩個 Target 也意味著,從 Gradle DSL kotlin { ohosArm64() } 一直到中間 IR 的 lowering 階段,Kotlin 編譯器都知道了 HarmonyOS 平台的存在。

接著就是讓 LLVM 後端真的能產出可執行的二進位,這一步簡單說就兩件事:

  • clang 參數:用畢昇 LLVM 19,並沿用 Linux 的 host-defines,因為 HarmonyOS 底層 libc 是 musl,工具鏈以 Linux ELF 衍生
  • 連結器Linker.kt 使用 class OhosLinker(targetProperties: OhosConfigurables) : LinkerFlags(...),並搭配 OhosConfigurables 做 dispatch

那 KMP 到這裡 Kotlin 到 ELF 的工具鏈就這樣接通了,接著就是產物:

  • 編譯器使用 HarmonyOS 官方畢昇 LLVM 19,並與 Kotlin/Native 內建 LLVM 解耦
  • 產物大致有:

    • libkn.so(業務通用動態庫)
    • libkn.a(靜態庫,供 hap 二次連結)
    • libkn_api.h(C 標頭,供宿主端 C/C++ 存取 Kotlin 匯出 API,與 libkn_api.h 配套)
    • .kexe(可執行檔)
  • 模組化編譯:透過 emitRuntime / emitStdlib / moduleIncludes 分別產出 runtime、stdlib、業務模組等多個 so,可按需載入、熱替換與排查符號問題

=

  • 快取:支援 per-file / per-klib 靜態快取,可加速 Debug 增量建置
  • DFX:內建 hilog 接入、crash 堆疊解析,Sanitizer 方面支援 ASAN

所以整個流程大概就是: Kotlin 原始碼 → Kotlin/Native 編譯器(帶 OHOS Target) → 畢昇 LLVM 19(OHOS 工具鏈) → ELF 靜態/動態庫 (.a/.so/.kexe) ,最後被 HarmonyOS 應用以 dlopen 方式載入:

CMP HarmonyOS

完成 KMP 的基礎之後,就是 CMP 在 HarmonyOS 上的 Skia 繪製,目前也有兩條路線:

  • 自繪製(skia 路徑)
  • 統一渲染(fusionRenderer 路徑)

自繪製

自繪製路徑和 iOS 的 KN 一致,CMP 自己持有一塊 GL Surface,自己 swap,HarmonyOS 這一側的載體是提供一個 ArkUI 的 XComponent,暴露一個原生 EGL Surface,外加觸控事件投遞:

  • ComposeArkUIViewController 作為入口類,接到 ArkUIViewController 的生命週期回呼後,會把 EGL 上下文與 Skia Surface 接起來
  • 幀驅動用 ChoreographerManager 接收 HarmonyOS vsync 訊號,然後送給 ComposeSceneRender 做組合與重繪

基本上都跟 ovCompose 沒什麼太大差別,一個媽生的。

統一渲染

這個就有意思了,透過 ArkUI RenderNode 作為掛載錨點,由 ArkUI 渲染執行緒驅動反向 draw 回呼,Compose 直接在 ArkUI 提供的 Canvas 上完成繪製,fusion 模式下 Compose 不再持有獨立 EGL/GPU 上下文,所以省去雙份 GPU 上下文與離屏 buffer 的開銷:

  • JsRenderNode(透過 NAPI / RenderNode JS API 同步)
  • CRenderNode(透過 Native C++ 直接掛載)

=

不過目前統一渲染的 ArkUINativeViewFusionRenderNode.kt 檔頭是:

但是實作上又是:

所以這是屬於華為的設計,還是和騰訊有關係?我也分不清楚了,但看起來還是更像是華為的實作,或者只是模板污染了?

所以看下來,目前 HarmonyOS 社群版本基本就是繼承了 KuiklyBase 和 ovCompose 的實作,算是這兩個的分支?而且目前已經合入了 JetBrains 上游 Kotlin 2.2.21 / Compose 1.9.2 ,還在加了 LTPO/DVSync 自適應幀率、CommonGC 全新演算法取代原 CMS 演算法等調整,所以也不全是騰訊的直接遷移。

不過問題來了,未來 KMP 和 CMP 在 HarmonyOS 等於是多分叉?比如:

  • JetBrains 的 KMP/CMP
  • 基於 JetBrains 的騰訊 Kuikly 和 ovCompose
  • 基於 Kuikly 和 ovCompose 的 CPF-KMP-CMP

或者後續完全分叉?開發者自己選用哪個?反正我暫時是沒搞懂。那麼如果是你,你會選哪個?

連結

atomgit.com/CPF-KMP-CMP…


原文出處:https://juejin.cn/post/7651954728705212422


精選技術文章翻譯,幫助開發者持續吸收新知。

共有 0 則留言


精選技術文章翻譯,幫助開發者持續吸收新知。
🏆 本月排行榜
🥇
站長阿川
📝16   💬1   ❤️1
463
🥈
我愛JS
📝1   ❤️1
22
評分標準:發文×10 + 留言×3 + 獲讚×5 + 點讚×1 + 瀏覽數÷10
本數據每小時更新一次
📢 贊助商廣告 · 我要刊登