🔮 什么是 Kotlin Multiplatform
Kotlin Multiplatform(KMP)是 JetBrains 推出的跨平台开发技术,允许开发者使用 Kotlin 编写可在多个平台上运行的共享代码。与其他跨平台方案不同,KMP 的核心思路是共享业务逻辑,保留各平台原生 UI。
2023 年 11 月,KMP 正式发布 Stable(稳定版)1.0,标志着该技术已达到生产就绪状态。Google 官方将其列为 Android 推荐的跨平台共享代码方案,Netflix、McDonald's、Cash App 等公司已在生产环境中使用 KMP。
1.1 KMP 解决了什么问题
在没有 KMP 之前,一个同时支持 Android 和 iOS 的团队需要维护两套完全独立的代码库:
- 同样的 API 调用逻辑,用 Kotlin 写一遍,用 Swift 再写一遍
- 同样的 JSON 解析模型,两端各自定义一次
- 同样的业务规则(如价格计算、表单验证),两端分别实现,容易产生差异 bug
- 同样的本地缓存策略,两端各自维护
KMP 将这些逻辑统一放在 shared 模块的 commonMain 中,Android 和 iOS 直接引用,从根本上消除了重复劳动和跨端不一致问题。
⚖️ 与竞品架构对比
理解 KMP 的最好方式是把它与 Flutter 和 React Native 进行架构层面的对比。
| 维度 | Kotlin Multiplatform | Flutter | React Native |
|---|---|---|---|
| 共享范围 | 业务逻辑(网络、数据库、状态) | 业务逻辑 + UI(全部) | 业务逻辑 + UI(大部分) |
| UI 渲染 | 各平台原生(Compose / SwiftUI) | Skia/Impeller 自绘引擎 | 映射到平台原生组件 |
| 语言 | Kotlin(共享)+ Kotlin/Swift(UI) | Dart | JavaScript / TypeScript |
| iOS 编译 | 原生机器码(Kotlin/Native) | ARM 机器码(AOT) | JavaScript(JSI 桥接) |
| 原生感 | 完全原生 | 高度一致但非原生 | 接近原生 |
| 推进方 | JetBrains + Google | Meta | |
| 学习曲线 | 需同时了解 Android + iOS | 学习 Dart 即可 | JS 开发者较容易上手 |
| 适用场景 | 现有 Android/iOS 项目逐步共享 | 全新项目,追求 UI 高度一致 | Web 团队转型移动开发 |
1.2 架构层次图
以下示意图展示了三种技术在架构层面的本质差异:
🔮 KMP 架构
┌─────────────┬─────────────┐
│ Android UI │ iOS UI │
│ (Compose) │ (SwiftUI) │
├─────────────┴─────────────┤
│ 共享业务逻辑 (Kotlin) │
│ 网络/数据库/状态/业务规则 │
└───────────────────────────┘
🎯 Flutter 架构
┌───────────────────────────┐
│ Flutter UI (Dart) │
│ Widgets / Skia 渲染引擎 │
├───────────────────────────┤
│ 业务逻辑 (Dart) │
├───────────────────────────┤
│ 平台通道 (MethodChannel)│
└───────────────────────────┘
1.3 KMP 的真正优势在哪里
✅ KMP 更适合的场景
- 已有 Android 应用,需要扩展 iOS
- 需要平台特定 UI/UX 设计
- 团队同时有 Android 和 iOS 工程师
- 对性能和平台一致性要求极高
- 使用大量平台特定 API(相机、蓝牙等)
⚠️ KMP 需要权衡的场景
- 全新项目且团队只会一门语言
- 需要 UI 在所有平台高度一致
- 团队没有 iOS/Swift 经验
- 需要快速原型,时间非常紧张
🧩 核心理念:共享层 + 平台原生 UI
KMP 项目的典型代码组织方式如下图所示:
1.4 expect / actual 机制
当某段代码在逻辑上是通用的,但底层实现依赖平台 API 时,KMP 提供了 expect/actual 机制。
expect:在 commonMain 中声明"我期望每个平台提供一个这样的实现"
actual:在 androidMain / iosMain 中提供真正的实现
ClassName.android.kt 和 ClassName.ios.kt,编译器会自动根据目标平台选择正确的文件。
🎯 支持的目标平台
KMP 支持将 Kotlin 代码编译到多个目标平台,每个平台使用不同的 Kotlin 编译器后端:
| 平台 | 编译器后端 | 运行时 | 成熟度 |
|---|---|---|---|
| Android | Kotlin/JVM | ART (Android Runtime) | ✅ 稳定 |
| iOS | Kotlin/Native | 原生机器码 (ARM64) | ✅ 稳定 |
| macOS | Kotlin/Native | 原生机器码 | ✅ 稳定 |
| Windows | Kotlin/Native | 原生机器码 (mingw) | ✅ 稳定 |
| Linux | Kotlin/Native | 原生机器码 | ✅ 稳定 |
| Web (Wasm) | Kotlin/Wasm | WebAssembly | 🔶 Beta |
| Web (JS) | Kotlin/JS | Node.js / Browser | ✅ 稳定 |
| JVM (桌面) | Kotlin/JVM | JVM | ✅ 稳定 |
1.5 build.gradle.kts 中的目标声明
🎨 Compose Multiplatform
Compose Multiplatform(CMP)是 JetBrains 在 KMP 基础上构建的 UI 共享层,将 Jetpack Compose 扩展到 iOS、桌面和 Web 平台。
🤖 Android
基于 Jetpack Compose,完全一致的 API,与 Android 生态无缝集成。
🍎 iOS (Beta)
使用 Skiko 渲染引擎在 iOS 上绘制 Compose UI,可访问 UIKit/SwiftUI 组件。
🖥️ Desktop (JVM)
基于 Skiko,在 macOS/Windows/Linux 桌面端运行完整 Compose 应用。
🌐 Web (Wasm)
通过 WebAssembly 在浏览器中运行 Compose UI,Alpha 阶段。
1.6 KMP 与 CMP 的关系
- KMP:共享业务逻辑(必选)
- CMP:共享 UI 代码(可选,适合需要 UI 高度一致的项目)
- 两者可以共存:共享业务逻辑 + 部分共享 UI + 部分平台原生 UI
🛠️ JetBrains 生态库
KMP 拥有一套经过专门适配的多平台库,这些库在 commonMain 中声明依赖,自动适配各目标平台:
- Ktor Client JetBrains 官方 HTTP 客户端库,多平台支持。Android 使用 OkHttp 引擎,iOS 使用 Darwin 引擎,API 在 commonMain 中完全统一。支持 ContentNegotiation、Auth、WebSocket 等插件。
- SQLDelight 根据 .sq SQL 文件自动生成类型安全的 Kotlin API。多平台驱动支持 Android (AndroidSqliteDriver)、iOS/Native (NativeSqliteDriver)、JVM (JdbcSqliteDriver)。Square 出品,与 KMP 深度集成。
- Kotlinx.Serialization JetBrains 官方 Kotlin 序列化库,支持 JSON / CBOR / Protobuf 等格式,在 KMP 所有目标平台上均可使用,与 Ktor 无缝配合。
- Kotlinx.Coroutines Kotlin 异步并发库,Flow / StateFlow / SharedFlow 等响应式原语,在 KMP 所有平台支持。iOS 需要注意主线程调度(使用 Dispatchers.Main)。
- Kotlinx.DateTime 多平台日期时间库,替代 java.util.Date / NSDate,提供统一的 Instant、LocalDate、TimeZone API。
- Koin 轻量级依赖注入框架,支持 KMP。在 commonMain 中声明模块,Android 使用 koin-android,iOS 调用 startKoin() 初始化。
- Coil 3 Android 图片加载库 Coil 的第 3 代,完整支持 KMP(Android / iOS / Desktop / Web),替代 Glide/Picasso 做多平台图片加载。
- SKIE Swift/Kotlin Interoperability Enhanced。让 iOS Swift 代码能以更自然的 Swift 风格使用 Kotlin 的 Flow、sealed class、coroutines,极大改善互操作体验。
📖 名词解释
- commonMain KMP 源集(Source Set),包含在所有目标平台上都能运行的纯 Kotlin 代码。这里只能使用 Kotlin 标准库和明确支持多平台的三方库,不能调用 Android SDK 或 iOS SDK 的 API。
- androidMain Android 平台专属源集,可以调用 Android SDK 的所有 API(Context、View、ActivityManager 等),也可以提供 expect 声明的 actual 实现。
- iosMain iOS 平台专属源集,可以调用 Objective-C / iOS SDK 框架(UIKit、Foundation、AVFoundation 等),为 iOS 提供 actual 实现。
- expect 在 commonMain 中声明一个"期望存在"的类、函数或属性,但不提供实现体。编译器强制要求每个目标平台提供对应的 actual 实现,否则编译报错。
- actual 在平台特定源集(androidMain / iosMain)中提供 expect 声明的具体实现。actual 函数签名必须与 expect 完全匹配。
- Kotlin/Native Kotlin 的原生编译器后端,将 Kotlin 代码编译为原生机器码,无需 JVM 运行时。iOS、macOS、Linux、Windows 目标使用此后端,编译结果可以作为原生库被 Swift/C 代码调用。
- XCFramework Apple 的通用框架格式,可以包含多种架构(arm64 真机 + x86_64/arm64 模拟器)的编译产物。KMP 将 shared 模块发布为 XCFramework,供 Xcode 项目引用。
- Source Set KMP 中的"代码集"概念,每个 Source Set 针对特定平台或平台组合。KMP 的 Source Set 层次结构是:commonMain → 中间集(如 appleMain)→ 平台集(iosMain / macosMain)。
🎯 本章小结
学完本章,你应该能够回答以下问题:
- KMP 与 Flutter 最本质的区别是什么?(提示:共享 UI vs 共享业务逻辑)
expect/actual机制解决了什么问题?- 为什么说 KMP 适合"渐进式迁移"?
- Compose Multiplatform 与 KMP 是什么关系?