Compose 能應用於跨平台,主要是基於 KMM 架構,KMM 的介紹可以查看官方文檔《Get started with Kotlin Multiplatform Mobile[1]》,我們來看下 KMM 的簡單架構:

commonMain 為通用層模塊,也可以被稱為平台無關層,如果 commonMain 涉及到平台相關操作的話,則需要定義 expect 方法,讓 xxxMain 模塊去 actual 實現這個方法,這樣,在不同的平台集成 KMM 時就可以實現各自平台的效果。
從 KMM 架構可以看出,一些通用的邏輯計算完全可以丟進 commonMain 來實現,以此來達到各端只維護一份代碼的目的,也算是提效了。
KMM 架構可以實現各端的通用邏輯,那基於 KMM 的 Compose 主要目的是為了實現各平台的 ui 統一。從 compose-jb[2] 倉庫來看,目前能復用的只有 Android 和 Desktop,想支持全跨平台的話,任務依然很艱巨,我們來看下簡單的架構圖:

Android 與 Desktop 能使用一份代碼來做到 ui 復用的主要原因是 jb 拷貝了一份 jetpack compose 代碼,然後實現了 jb-compose 和 compose-desktop,jb-compose 為 commonMain 層使用的通用模塊,jetpack-compose 為 Android 所集成的平台模塊,compose-desktop 為 desktop 所集成的平台模塊,:
既然是拷貝 jetpack compose 來實現一份代碼達到 ui 復用,所以,在編寫 desktop 代碼時,會發現各個 import 的組件包名都是 androidx,確實會有點奇奇怪怪,即使以後復用到了 iOS ,這塊 androidx 包名也無法被擺脫。
這裡面還有一個小細節,commonMain 明明依賴的是 jb-compose,Android 依賴的是 jetpack-compose,這兩個庫參與打包的話,難道不會發生 duplicate class 錯誤嘛?這裡可以看下 ComposePlugin 插件的 RedirectAndroidVariants 類,在 Android 項目編譯的時候,會將 jb-compose 依賴替換成 jetpack-compose。
❞這裡面有個小插曲,在我看 compose-jb 項目的 sample 時,看到 todoapp[3] 有 iOS 項目,難道 jb 開始支持 iOS 了?當我打開 README 時發現,咋被耍猴了:

既然目前可以支持 Android 和 Desktop,那麼,我們在開發界面時需要注意哪些呢?我大致列了一下:
在 Android 平台,可以使用 androidx.navigation:navigation-compose 來實現組件路由,但該組件 jb 並沒有移植到 jb-compose 中,所以,無法在兩個平台上實現復用,好在瀏覽 jb-compose 項目的 issue 時找到了一個可替代的方案 Decompose[4]。
Decompose 支持的能力有:
Decompose 支持的平台有:
試着跑了下 sample,效果如下:

在 jb-compose 里的 todoapp[5] sample 中,也用到了該庫:


為了統一兩端獲取 Drawable 資源的差異,可以將 Android 中 R.drawable 獲取資源的方式改成 resources.getIdentifier ,但如果 Android 項目有用到如 AndResGuard[6] 等資源混淆的話,則這塊代碼將會報錯,需要做 keep 處理。
如果項目有資源混淆需求的話, 建議直接定義獲取圖片的方法,如:

多語言的實現與圖片資源設置類似:

在運行 desktop 項目時遇到中文多語言亂碼問題,解決辦法是將項目編碼改成 UTF-8 即可:

在整個調研和使用下來,感覺 Compose 跨平台還有很長的路要走,google 一直在埋頭發展自己的 jetpack compose,如果 jb 與 google 能雙向奔赴的話,那該有多好。
我覺得,如果有一款能直接讓客戶端的編程語言(kotlin、swift)直接實現跨端,而不是再學習一款新的語言(dart) 來實現多平台開發,那真是一件美好的事情。
ReferenceGet started with Kotlin Multiplatform Mobile: https://kotlinlang.org/docs/multiplatform-mobile-getting-started.html》
[2]compose-jb: https://github.com/JetBrains/compose-jb
[3]todoapp: https://github.com/JetBrains/compose-jb/tree/master/examples/todoapp
[4]Decompose: https://arkivanov.github.io/Decompose/
[5]todoapp: https://github.com/JetBrains/compose-jb/tree/master/examples/todoapp
[6]AndResGuard: https://github.com/shwenzhang/AndResGuard
[7]KMPCompose: https://github.com/MRwangqi/KMPCompose
[8]java中如何實現多語言切換: https://zhidao.baidu.com/question/58590642.html
---END---
推薦閱讀
10個問題帶你看懂 Compose 跨平台
深入理解跨平台技術的現狀與本質
Compose Multiplatform 實戰聯機小遊戲
D-KMP 架構:聲明式UI + Kotlin跨平台


交個朋友
