Loading... ## KMM , KMP ### Kotlin Multiplatform <div class="tip inlineBlock info simple small"> **Kotlin Multiplatform** is a technology that allows you to create applications for various platforms and efficiently reuse code across them while retaining the benefits of native programming. Your applications will run on iOS, Android, macOS, Windows, Linux, and more. </div> KMP 是一种使用 Kotlin 代码来编写跨平台语言的技术。让你将同一套**业务**代码同时运行在多个平台,同时能够保持原生编程的优势。因为跨平台的只是业务部分,具体的UI,可以使用原生开发,也可以使用 CMP ### Kotlin Multimobile KMP 支持的平台不止局限于移动端,甚至包括 Web 以及桌面平台,所以 KMM 可以理解为 KMP 在移动端的一个子集,现在都用 KMP 来统一描述项目,而 KMM 则淡化为了工具链中的一种使用方式  ## 神奇的 Kotlin <div class="panel panel-default box-shadow-wrap-lg goal-panel"> <div class="panel-heading"> Kotlin 发展历程 </div> <div class="padder-md wrapper"> <div class="streamline b-l m-b"><div class="sl-item b- b-l"> <div class="m-l"> <div class="text-muted">2010-07</div> <p>JetBrains 启动 Kotlin 项目,目标是构建一种更现代、更安全、更简洁的 JVM 语言。</p> </div> </div><div class="sl-item b-info b-l"> <div class="m-l"> <div class="text-muted">2011-07</div> <p>Kotlin 首次对外公开,在 JVM Language Summit 上亮相。</p> </div> </div><div class="sl-item b-dark b-l"> <div class="m-l"> <div class="text-muted">2012-02</div> <p>Kotlin M2 版本发布,实验性支持编译为 JavaScript(Kotlin/JS)。</p> </div> </div><div class="bg-light wrapper-sm m-l-n m-r-n m-b r r-2x">由于当时工具链不完善,Kotlin/JS 没有引起太多关注。</div><div class="sl-item b-black b-l"> <div class="m-l"> <div class="text-muted">2016-02</div> <p>Kotlin 1.0 正式发布,成为稳定版本,兼容 Java。</p> </div> </div><div class="sl-item b-warning b-l"> <div class="m-l"> <div class="text-muted">2017-05</div> <p>Google I/O 宣布 Kotlin 成为 Android 官方支持语言。</p> </div> </div><div class="sl-item b-primary b-l"> <div class="m-l"> <div class="text-muted">2017-12</div> <p>Kotlin 1.2 发布,Kotlin Multiplatform(KMP)开始预览,支持共享业务逻辑代码。</p> </div> </div><div class="sl-item b-danger b-l"> <div class="m-l"> <div class="text-muted">2018-08</div> <p>Kotlin/Native 首个稳定版本发布,支持 iOS、Linux 等平台的原生代码编译。</p> </div> </div><div class="sl-item b- b-l"> <div class="m-l"> <div class="text-muted">2019-05</div> <p>Google I/O 再次发声,宣布 Kotlin 成为 Android 的首选语言。</p> </div> </div><div class="bg-light wrapper-sm m-l-n m-r-n m-b r r-2x">JetBrains 随后推出 Kotlin Multiplatform Mobile(KMM)工具,提升 Android+iOS 跨平台开发体验。</div><div class="sl-item b-dark b-l"> <div class="m-l"> <div class="text-muted">2023-11</div> <p>Kotlin 1.9.20 发布,KMP 正式进入稳定阶段,适用于生产环境。</p> </div> </div></div></div></div> 从 Kotlin 的发展上可以看到,Kotlin 从设计之初就是为了打造高效的跨平台语言, Kotlin K2 Compiler 的推出也极大的提高了开发的效率,目前 Kotlin 支持以下平台的编译目标: - Kotlin/JVM - Kotlin/Native - Kotlin/JS - Kotlin/Wasm(Alpha) 对于到具体平台上,编译实现的方式也有所不同 ### Kotlin/JVM 在 Android 平台以及后端上,由于安卓系统内置的 ART/DVM 虚拟机本身就使用 Kotlin/Java 语言,而传统后端一般使用的都是标准的 JVM 环境,所以在这两个平台编译时,会使用 Kotlin/JVM 这种相对“原始”的实现: ```mermaid flowchart LR kj[Kotlin/JVM] -->jvm(JVM IR) jvm --> jvmCode[JVM 字节码] jvmCode -->dex[DEX] jvmCode -->jar[JAR] dex -->APK[APK/AAB] jar -->server[Server JVM] APK -->android[Android JVM] ``` ### Kotlin/Native 而在 iOS 或桌面端等无虚拟机的场景,则会使用 Kotlin/Native 编译为原生机器码,Kotlin/Native 会首先将 Kotlin 代码编译为 LLVM IR 这是一种平台无关的中间表示,同一份 LLVM IR 可以编译为不同架构的机器码,从而实现跨平台: ```mermaid flowchart LR KN[Kotlin/Native] -->LLVM(LLVM IR) LLVM -->Mach[Mach-O] LLVM -->dll[lib/dll] LLVM -->so[so/a] Mach -->Mach-ios[framework] Mach -->Mach-mac[dylib] dll -->EXE[exe] so -->RPM[RPM/DEB] Mach-ios -->IPA[IPA] Mach-mac -->APP[APP] IPA -->ios[iOS] APP -->macOs[macOS] EXE -->Win[Windows] RPM -->Linux[Linux] ``` ### Harmony Next <div class="tip inlineBlock info"> [快手团队鸿蒙 KMP 落地实践](https://blog.jetbrains.com/wp-content/uploads/2024/12/day1\_5-KMP-.pdf) </div> 鸿蒙支持 JS 语言,同时也是类 UNIX 系统,理论上 Kotlin/JS 和 Kotlin/Native 都是能够编译到鸿蒙设备上使用的 ## KMP 的现状 ### 性能 在上面的编译过程可以看到,KMP 在各个平台都是采用原生二进制来引入的,所以通过这种方式引入的代码和原生基本接近,对比早期的 React Native 少了 JS Bridge 的开销,对比 Flutter 少了 Dart VM 的开销,因为 Kotlin/Native 直接依赖原生平台的运行时 ### 灵活 KMP 可以通过多种方式引入,你可以用 KMP 共享部分逻辑,也能共享全部逻辑,配合 CMP ,可以直接构建完整的跨平台应用,甚至可以和 Flutter 结合(不会真有人想这么干吧) ### 生态 Kotlin 的生态目前肯定是越来越好的,Kotlin 也推出了 [Klibs.io — Search 2200+ KMP projects](https://klibs.io/) 来检索可以在 KMP 中使用的库,以下这些常用的工具都有比较好的解决方案: - 网络请求 [Ktor](https://ktor.io/) - 依赖注入 [Koin](https://github.com/InsertKoinIO/koin) - 图片加载框架 [coil](https://github.com/coil-kt/coil) - 响应式编程 [Reaktive](https://github.com/badoo/Reaktive) 等等 ## Compose | | Jetpack Compose | Compose Multiplatform | | ----------- | --------------- | -------------------------- | | 支持的平台 | Android | Android, iOS, Desktop, Web | | 开发/支持者 | Google | Jetbrains | CMP 是 Jetbrains 公司在 Jetpack Compose 上开发出来的“扩展”,并不直接属于 Google 所以和 Flutter 并不冲突 KMP 可以作为共享业务逻辑层单独使用,而 CMP 必须配合 KMP 一起使用,不管是替换部分 UI 还是全部 UI,CMP 可以看作 KMP 的 UI 支持,不是 KMP 的一部分,但是可以用来补充 KMP 缺少的 UI 能力 但是 CMP 本质上还是基于 Jetpack Compose 开发,所以使用的 API 基本一致,唯一的区别就是有些 Package 的命名空间位于 `org.jetbrains.compose` 而不是 `androidx.compose` 下 ### 项目结构 #### CMP 在 CMP 项目中,我们会同时共享 UI 和业务逻辑,在 composeApp 中包含了所有的共享代码,而 iosApp 则是用与编译到 iOS 产物的模块  在 composeApp,也就是所有平台共享的文件夹中,又区分了不同平台的 Main 文件夹,其中公共逻辑可以直接在 commonMain 中定义,而需要不同平台分别实现的逻辑,KMP 提供了 `expect` 和 `actual` 关键字,分别用与定义跨平台接口,以及对应的平台实现  #### KMP KMP 项目的项目结构和 CMP 差不多,但是还是有写差别  在 CMP 中,我们将业务和 UI 代码都写在 composeApp 中,而在 KMP 中我们不共享 UI,所以提取出了一个 shared 文件夹,来单纯存放业务逻辑 ## CMP 渲染原理 ### Skia Jetbrains 自己封装了一层 Kotlin 到 Skia 的框架,叫做 [Skiko](https://github.com/JetBrains/skiko) (short for Skia for Kotlin),Skia 本身是一个通用的跨平台 2D 图形库,很多地方都有它的影子,包括 Andrid 系统等等,Flutter 也使用了 Skia 作为渲染方案,才能做到跨平台的高度一致性,而 CMP 不出意外的也选择了 Skia,但是对比于 Flutter 还是稍后不同 Skia 的传统 GPU 后端 Ganesh 非常依赖着色器的动态编译,如果着色器编译速度更不上,就会出现卡顿的情况,而 Skia 目前也在推进下一代的 GPU 后端 Graphite,新的后端对 Vulkan 和 Metal 有了更好的支持,相信未来 Skia 的性能会更上一层 为啥 Skia 这么依赖着色器编译,但是安卓上的原生 APP 就这么流畅呢?这是因为安卓系统层面上支持的 HWUI HWUI 在 Skia 上构建,支持硬件加速,同时有多层的缓存机制,可以复用很多的 GPU 资源,甚至可以在不同的 APP 间共享缓存,简单点说,使用系统的 Skia ,在你的 APP 启动之前,着色器就已经处于预热好的状态了 对比到具体的应用中,在 Android 平台,CMP 没有像 Flutter 一样内置 Skia,而是使用了系统的 Skia,这就意味着使用 CMP 开发的 Android APP 可以享受到和原生一样的渲染优化,但是在 iOS 平台上,则没有这些优化,对比与 Flutter 的 impeller 来说,impller 中所有的着色器都会离线编译到引擎中,可以期待一下 Graphite 为 Skia 带来新的提升,不过 iOS 设备本身性能较大部分安卓设备更好,所以带来的体感差距和原生相比也不太明显(肯定不是因为60hz屏幕) <div class="tip inlineBlock warning"> 在 Flutter 3.32 版本的 Release Note 中 Flutter 提到,Due to our increasing confidence in Impeller’s stability and performance, the ability to opt-out of Impeller on newer Android devices will be removed in an upcoming stable release.(SDK 29) </div> 当然,不管是 Skia 还是 impeller ,在目前正常的使用场景下性能问题都不大,如果你在用的时候发现特别卡,那么应该考虑一下是不是人的问题  © 允许规范转载 打赏 赞赏作者 微信 赞