Compose Multiplatform 如何做到跨平台
严格来说,Jetpack Compose 本身只面向 Android,以及 Wear OS 等 Google 官方变体。真正实现跨平台的是 JetBrains 主导的开源项目 Compose Multiplatform。它把 Compose 从 Android 体系中剥离出来,移植到 Desktop、iOS、Web 等平台,让开发者可以用同一套 Kotlin 代码编写声明式 UI。
一句话概括:Compose 跨平台的本质,是把无 Android 依赖的 Compose Runtime 抽出来作为通用引擎,用 Skia 做非 Android 平台的统一渲染,再用 Kotlin Multiplatform 的 expect/actual 处理平台差异,从而实现“UI 代码一次编写,多平台运行”。
下面综合三份材料,从概念、架构、渲染、KMP 机制、工程结构、平台现状、与 Flutter 的异同、限制与选型等角度,写一篇完整长文。
一、概念澄清:Jetpack Compose 与 Compose Multiplatform 不是一回事
很多人会把 Jetpack Compose 和 Compose Multiplatform 混为一谈,但两者有明确边界。
| 特性 | Jetpack Compose(Google) | Compose Multiplatform(JetBrains) |
|---|---|---|
| 维护方 | JetBrains | |
| 目标平台 | 仅 Android | Android、iOS、Desktop、Web |
| 核心库 | androidx.compose.* | org.jetbrains.compose.* + androidx |
| Material Design | Material 2/3(Android) | Material 3(跨平台统一) |
| 适用场景 | 纯 Android 应用 | 需要共享 UI 的多平台项目 |
因此,准确说法是:Jetpack Compose 是 Android 的 UI 工具包;Compose Multiplatform 是 JetBrains 基于 Compose 构建的跨平台 UI 框架。 在 Android 上,Compose Multiplatform 可以直接复用 Jetpack Compose;在其他平台上,它通过 Skia/Skiko 和平台桥接层实现渲染与交互。
二、核心架构:分层设计,共享与适配并存
Compose Multiplatform 能够跨平台,根本原因是 Compose 的架构被分层解耦了。它大致可以分为以下几层:
┌─────────────────────────────────────┐
│ Common UI 代码(你的业务代码,一套) │
├─────────────────────────────────────┤
│ Compose Runtime(跨平台通用) │ ← 重组、状态管理、协程调度
├─────────────────────────────────────┤
│ Compose UI Core(通用抽象接口) │ ← 布局、绘制、输入处理
├──────────────┬──────────────────────┤
│ Skia 渲染层 │ 各平台原生集成层 │
├──────────────┤ │
│ Desktop/iOS │ Android 直接用 │
│ 用 Skia 渲染 │ 系统 Canvas/RenderNode│
└──────────────┴──────────────────────┘
更细一点,可以拆成这些层次:
-
Compose Compiler
作为 Kotlin 编译器插件,负责处理@Composable注解,进行静态检查并生成必要代码。这一层与平台无关,被所有平台共享。 -
Compose Runtime
纯 Kotlin 代码,不依赖任何平台 SDK。它负责状态管理、重组(Recomposition)、Composition、Slot Table、快照系统等。它只依赖 Kotlin 标准库和协程,是跨平台的基石。2021 年 JetBrains 接手时,关键一步就是把 runtime 从 Android 中抽出来。 -
Compose UI Core
定义布局、绘制、输入处理等通用抽象接口,但不包含具体平台实现。它让上层 UI 代码可以平台无关地描述界面。 -
Compose Foundation & Material
提供Column、Row、Text等基础布局组件,以及 Material 设计规范组件。Compose Multiplatform 中 Material 3 是跨平台统一的。 -
Platform Backends(平台后端)
针对每个目标平台提供具体的渲染和事件实现。Android 使用原生视图系统,iOS、Desktop、Web 则主要依赖 Skia/Skiko 或浏览器 Canvas。
这种分层的关键意义是:UI 描述、状态管理、布局抽象可以共享;渲染和平台集成按平台适配。
三、渲染机制:Android 复用原生,其他平台主要靠 Skia
Compose Multiplatform 并不是所有平台都用同一套自绘引擎“包打天下”。它的策略是:
- Android:直接复用 Jetpack Compose 的渲染管线,使用 Android 系统自带的硬件加速 Canvas、View/RenderNode 等。这样能获得最佳性能和系统兼容性。
- 非 Android 平台:主要依赖 Skia 图形库进行绘制。Skia 是 Google 的 2D 图形库,也是 Chrome、Android 底层的渲染引擎之一。
- iOS:通过 Skiko(Skia 的 Kotlin 绑定)调用,可用 Metal 加速,同时通过
UIKitView等机制与 UIKit 桥接。 - Desktop(JVM):基于 Skia,通过 JNI/JNA 调用本地 GPU,可走 OpenGL、Vulkan、Metal、DirectX 等底层图形 API。
- Web(Wasm):编译为 WebAssembly,在浏览器 Canvas API / WebGL 中渲染。
这种设计的好处是:非 Android 平台可以获得像素级一致的跨平台 UI,不依赖平台原生控件,行为完全可控,思路类似 Flutter。 同时,Android 又保留了原生渲染的性能和兼容性优势。
各平台渲染后端可总结如下:
| 平台 | 成熟度 | 渲染方式 |
|---|---|---|
| Android | ✅ 稳定(即 Jetpack Compose) | Android View / RenderNode / 系统 Canvas |
| Desktop(JVM) | ✅ 稳定 | Skia + OpenGL/Vulkan/Metal |
| iOS | ✅ 稳定(1.9 起 Stable) | Skia/Metal via Skiko,UIKit 桥接 |
| Web(Wasm) | ⚠️ Alpha/实验性 | Skia → WebGL/Canvas,编译为 Wasm |
关键点:除了 Android 外,其他平台主要依赖 Skia 图形引擎来保证像素级一致性渲染;Android 则保持原生渲染以获得最佳性能和兼容性。
四、Kotlin Multiplatform:跨平台的“骨架”与平台差异处理
Compose Multiplatform 不是孤立存在的,它与 Kotlin Multiplatform(KMP) 深度绑定。KMP 提供了代码共享和平台特定代码分离的基础设施。
1. 源代码集(Source Sets)
项目代码被组织到不同源集中:
commonMain:所有平台共享的 Compose UI、业务逻辑、Repository 接口。androidMain:Android 平台实现与入口。iosMain:iOS 平台实现与入口。desktopMain:桌面平台实现与入口。
一个典型工程结构如下:
composeApp/
├── src/
│ ├── commonMain/ # 共享的 Compose UI、业务逻辑、Repository 接口
│ │ └── kotlin/
│ │ └── App.kt # 共享的根 Composable
│ ├── androidMain/ # Android 入口 MainActivity 及平台实现
│ ├── iosMain/ # iOS 入口 MainViewController 及平台实现
│ └── desktopMain/ # 桌面入口 main.kt 及平台实现
关键原则:commonMain 不应直接依赖任何 Android 特有 API,如 Context、Activity,否则会破坏跨平台性。
2. expect/actual 机制
这是 KMP 处理平台差异的核心。在 commonMain 中用 expect 声明“预期” API,然后在各平台源集中用 actual 提供具体实现。编译器会确保每个 expect 都有对应的 actual。
例如:
// commonMain
expect fun getPlatformName(): String
@Composable
fun App() {
var count by remember { mutableStateOf(0) }
MaterialTheme {
Column {
Text("Hello, ${getPlatformName()}!")
Button(onClick = { count++ }) {
Text("Clicked $count times")
}
}
}
}
// androidMain
actual fun getPlatformName(): String = "Android ${Build.VERSION.SDK_INT}"
// iosMain
actual fun getPlatformName(): String = UIDevice.currentDevice.systemVersion
对于更复杂的平台对象,也可以这样:
// commonMain
expect class PlatformContext
@Composable
expect fun getPlatformName(): String
// androidMain
actual typealias PlatformContext = android.content.Context
@Composable
actual fun getPlatformName(): String = "Android ${Build.VERSION.SDK_INT}"
// iosMain
actual class PlatformContext(val viewController: UIViewController)
@Composable
actual fun getPlatformName(): String = UIDevice.currentDevice.systemVersion
3. Gradle 与资源管理
Compose Multiplatform 使用 org.jetbrains.compose Gradle 插件统一管理多平台依赖和资源。它还提供跨平台资源访问 API,包括图片、字符串、字体等,并自动处理各平台的资源目录结构差异。
4. 平台特定能力集成
对于相机、GPS、生物识别、文件系统、传感器等无法统一的原生功能,采用分层策略:
- 共享层
commonMain:定义平台无关接口,或使用expect声明。 - 平台层:通过
actual实现,调用原生 API。 - 互操作:例如在 iOS 上通过
UIKitView将原生UIView嵌入 Compose UI,实现与原生组件的互操作。
这样,UI 主体写一次,平台相关能力在各平台层分别实现。
五、Compose Multiplatform 的四大技术支柱
综合来看,Compose Multiplatform 的跨平台能力可以归纳为四大支柱:
-
架构分层:UI 与平台解耦
Compose Runtime 纯 Kotlin,负责状态与重组;Compose UI Core 定义通用抽象;Platform Backends 提供各平台实现。 -
各平台渲染后端
Android 用原生 View/RenderNode/Canvas;iOS、Desktop、Web 主要用 Skia/Skiko、Metal、OpenGL、Vulkan、WebGL、Canvas 等。 -
Kotlin Multiplatform 生态整合
UI 层共享的同时,数据层、网络层、存储层也可以通过 KMP 的expect/actual机制共享。Gradle 插件统一管理依赖和资源。 -
平台特定 API 处理
相机、GPS、生物识别等通过expect/actual和各平台原生桥接实现。
这四者结合,才实现了“UI 代码一次编写,多平台运行”。
六、与 Flutter 的异同
Compose Multiplatform 和 Flutter 在思路上有相似之处,也有明显区别。
相同点:
- 都用自绘渲染引擎保证跨平台一致性,而不是简单包装原生控件。
- 都追求像素级一致、行为可控。
- 都希望减少多平台 UI 开发成本。
不同点:
- Compose Multiplatform 复用 Kotlin 生态,业务逻辑层可以和 Android/iOS 原生代码共享,是 KMP 的一部分。
- Flutter 使用 Dart,通常需要重写业务逻辑和生态依赖。
- Compose Multiplatform 在 Android 上复用 Jetpack Compose 原生渲染,而不是完全自绘。
- Flutter 更接近“全平台统一自绘”,Compose Multiplatform 则是“Android 原生 + 非 Android 主要 Skia”的混合策略。
因此,对于已经使用 Kotlin、KMP 或 Android 原生开发的团队,Compose Multiplatform 的迁移和共享成本可能更低。
七、平台现状与成熟度(截至 2026 年)
材料给出的现状如下:
| 平台 | 成熟度 | 渲染方式 |
|---|---|---|
| Android | ✅ 稳定(即 Jetpack Compose) | 系统 Canvas |
| Desktop (JVM) | ✅ 稳定 | Skia |
| iOS | ✅ 稳定(1.9 起 Stable) | Skia/Metal via Skiko |
| Web (Wasm) | ⚠️ Alpha/实验性 | Skia → WebGL/Canvas |
这意味着:
- Android、Desktop、iOS 已经可以用于生产项目。
- Web 端仍处于 Alpha/实验性阶段,需要谨慎评估。
- iOS 自 1.9 起 Stable,说明 Compose Multiplatform 在移动端跨平台已经具备较强可用性。
八、限制与选型建议
Compose Multiplatform 并非万能。在以下场景中需要仔细评估:
- 高度依赖原生体验的应用:如复杂视频编辑、深度地图交互、严格遵循平台设计规范的应用,跨平台共享 UI 的收益可能被适配成本抵消。
- 平台能力的深度集成:支付、推送、复杂蓝牙通信、生物识别等功能,仍需要编写大量平台特定代码。
- Web 端成熟度:目前仍是 Alpha/实验性,不适合对稳定性要求极高的 Web 生产项目。
commonMain污染:如果共享层直接依赖 AndroidContext、Activity,跨平台性会被破坏。
选型建议可以总结为:
| 项目类型 | 建议 |
|---|---|
| 纯 Android 项目 | 继续用官方 Jetpack Compose |
| 需要共享 UI 的多平台项目 | 使用 Compose Multiplatform |
| 仅需共享逻辑、UI 各端独立 | 使用 KMP + 各端原生 UI |
九、总结
综合三份材料,Jetpack Compose 跨平台的核心机制可以概括为:
Jetpack Compose 本身只面向 Android;Compose Multiplatform 由 JetBrains 主导,通过分层解耦把 Compose Runtime 从 Android 中抽离出来,使其成为纯 Kotlin 的通用状态管理和 UI 描述框架。然后,Android 复用原生渲染,非 Android 平台主要依赖 Skia/Skiko 进行统一渲染,再用 KMP 的 expect/actual、source sets、Gradle 插件和资源管理处理平台差异。最终实现“UI 代码一次编写,多平台运行”,同时保留各平台的原生能力。
它的本质不是让 Android 代码直接跑在其他平台上,而是:
- 共享声明式 UI 范式;
- 共享 Compose Runtime 与 UI 抽象;
- 按平台适配渲染后端;
- 用 KMP 处理平台特定能力;
- 在一致性与原生体验之间做分层权衡。
对于熟悉 Jetpack Compose 的开发者来说,Compose Multiplatform 提供了一条较低学习成本的跨平台路径:用同一套 Kotlin 代码构建 Android、iOS、Desktop,并逐步探索 Web。它既不像 Flutter 那样完全另起炉灶,也不是简单包装原生控件,而是站在 Kotlin Multiplatform 生态之上,把 Compose 的声明式 UI 能力扩展到了更广阔的平台。
更多推荐



所有评论(0)