Skip to content

Kotlin Multiplatform:共享逻辑与 Compose Multiplatform

Kotlin Multiplatform(KMP)让一套 Kotlin 业务代码在 Android、iOS 等多端共享,UI 可以继续用各端原生写,也可以进一步用 Compose Multiplatform(CMP)连 UI 一起共享。理解 KMP 的第一件事:它不是 Flutter / React Native 那样的「一套 UI 处处跑」,而是「共享逻辑、保留原生」——想共享哪一层,决定你该怎么用它。

定位:共享什么,不共享什么

先在技术全景与选型里确认过结论:KMP 的正确姿势是共享业务逻辑层。具体分三层看:

是否共享说明
业务逻辑(用例、规则、状态机)✅ 共享语言无关的「做什么」,天然值得共享
数据层(网络、存储、领域模型)✅ 共享Ktor / SQLDelight / kotlinx.serialization 都有多平台实现
UI 层⚖️ 可选默认各端原生 UI(Android = Jetpack Compose / XML,iOS = SwiftUI);想连 UI 一起共享再上 Compose Multiplatform

一句话判断:

  • 目标是「少写两遍业务代码、保留两端原生体验」→ KMP(逻辑共享 + 原生 UI)
  • 目标是「一套 UI 代码跑两端、外观像素级一致」→ Flutter
  • 目标是「复用 React 生态、快速铺两端」→ React Native

对比细节见 FlutterReact Native。KMP 的隐性前提是团队熟悉 Kotlin/JVM 生态(Kotlin 语言速览见 Android 开发),否则学习曲线是双份的。

源集与编译目标

KMP 一个模块可以同时面向多种目标平台:

  • Android:编译为 JVM 字节码(作为 Android library 被 app 依赖);
  • iOS:用 Kotlin/Native 编译为静态/动态 framework,嵌入 Xcode 工程被 Swift 调用;
  • 桌面:macOS(JVM 或 Native)、Windows / Linux(JVM 或 Native);
  • Web:JavaScript 与 WebAssembly(wasmJs)。

代码按「源集」组织,依赖关系向下包含:

commonMain            ← 共享代码:业务逻辑、接口、模型
 ├── androidMain      ← Android 专属实现 / actual
 └── iosMain          ← iOS 专属实现 / actual(iosArm64 / iosSimulatorArm64 共享)

依赖只会从「上层源集」流向「下层源集」:commonMain 里的代码只能用「所有目标平台都有」的 API,平台差异通过 expect / actual 桥接。

expect / actual:描述一次,各端实现

commonMain 里声明期望,每个平台源集里给实际实现

kotlin
// commonMain:只声明,不实现
expect fun currentPlatform(): String

// androidMain
actual fun currentPlatform(): String = "Android"

// iosMain
actual fun currentPlatform(): String = "iOS"

使用约束:

  • expect 修饰的函数 / 属性 / 类,每个已启用的目标源集都必须有对应 actual,否则编译报错;
  • 官方库通常已提供 actual(如 kotlinx.datetimekotlin.time),日常业务代码真正要自己写 expect/actual 的场景不多——遇到差异先查库,再考虑自造;
  • 库作者可以用「默认实现 + 可覆盖」把多数平台兜住,减少使用方手写 actual 的负担。

Gradle 工程与 iOS 集成

KMP 模块用 kotlin-multiplatform 插件声明目标与依赖:

kotlin
// build.gradle.kts(KMP 共享模块;版本取 2026 当前稳定线,示例仅示意 API 形态)
plugins {
    kotlin("multiplatform")
    kotlin("plugin.serialization")
}

kotlin {
    androidTarget()                                  // Android
    listOf(iosArm64(), iosSimulatorArm64()).forEach { // iOS 真机 + 模拟器
        it.binaries.framework {
            baseName = "Shared"                      // 暴露给 Swift 的 framework 名
            isStatic = true
        }
    }

    sourceSets {
        commonMain.dependencies {
            implementation("io.ktor:ktor-client-core:3.x")
            implementation("io.ktor:ktor-client-content-negotiation:3.x")
            implementation("io.ktor:ktor-serialization-kotlinx-json:3.x")
            implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.x")
            implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.8.x")
        }
        androidMain.dependencies {
            implementation("io.ktor:ktor-client-okhttp:3.x")   // Android 网络引擎
        }
        iosMain.dependencies {
            implementation("io.ktor:ktor-client-darwin:3.x")   // iOS 网络引擎
        }
    }
}

iOS 侧集成要点:

  • Xcode 工程通过「Run Script」阶段调用 Gradle 生成 framework(官方模板里是 embedAndSignAppleFrameworkForXcode 一类的封装),或用 CocoaPods / SPM 方式接入;
  • 模拟器与真机架构都要配:常见漏项是只配了 iosArm64,模拟器跑不起来;
  • framework 是编译产物,业务改动后要重新执行生成,开发时要让「改共享代码 → 重新生成 → Xcode 重新链接」的链路尽量短(或直接用 Compose Multiplatform 工程省掉手动集成)。

共享层依赖选型

共享层能做多深,取决于生态里有没有对应多平台库:

能力常用选型备注
网络Ktor Client各端选引擎:OkHttp(Android)/ Darwin(iOS)/ CIO / JS
序列化kotlinx.serializationplugin.serialization@Serializable 数据类
本地存储SQLDelight、Room(KMP)、DataStore(KMP)SQLDelight 生成类型安全查询,多端一致
异步 / 响应式kotlinx.coroutines、Flow多端原生支持,是共享层的地基
依赖注入Koin、Kodein均有 multiplatform 支持
时间 / 平台能力kotlinx-datetime、官方平台库尽量避免自己写 expect/actual

一个共享网络层的最小例子:

kotlin
// commonMain:共享仓库 + Ktor + kotlinx.serialization
import io.ktor.client.*
import io.ktor.client.call.*
import io.ktor.client.plugins.contentnegotiation.*
import io.ktor.client.request.*
import io.ktor.serialization.kotlinx.json.*
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.Json

@Serializable
data class Repo(val fullName: String, val description: String? = null)

fun createHttpClient() = HttpClient {
    install(ContentNegotiation) {
        json(Json { ignoreUnknownKeys = true })
    }
}

class RepoApi(private val client: HttpClient) {
    suspend fun topRepos(org: String): List<Repo> =
        client.get("https://api.github.com/orgs/$org/repos").body()
}

UI 层只要把 RepoApi 当普通依赖使用即可:Android 侧包成 ViewModel + StateFlow(见 Android 开发 的 MVVM 部分),iOS 侧包成 ObservableObject / @Observable 供 SwiftUI 消费,业务判断全部复用上面的共享代码。

iOS 互操作:从 Swift 调共享代码

Kotlin/Native 与 Swift 互操作有几条要提前知道的现实:

  • suspend 函数 → Swift async:Kotlin 的挂起函数在 Swift 侧可当 async 函数调用(编译链支持),异步衔接相对顺滑;
  • Flow → Swift 需要转换:Flow 不会自动变成 Swift 的 AsyncSequence,通常用 AsyncStream 手动桥接,或用 SKIE 这类工具自动生成更友好的 Swift API;
  • 内存模型纪律:Kotlin/Native 采用新内存模型后,对象不能随意跨线程共享。Swift 回调里把共享层对象塞进后台队列、或反过来在非主线程改共享层可变状态,是 iOS 集成里最常见的崩溃源;
  • 顶层可变状态要克制:共享层尽量设计成「显式传依赖、不可变模型 + 单向数据流」,在 iOS 侧会少踩很多线程坑。

Compose Multiplatform:当你想连 UI 一起共享

Compose Multiplatform(CMP)把 Jetpack Compose 延伸到 iOS / 桌面 / Web:

  • Android:与原生 Compose 同源,体验一致;
  • iOS:编译为 Kotlin/Native,渲染走 Skia,用 UIKit 承载(官方状态以当前版本为准,移动端 iOS 支持已从预览走向稳定);
  • 桌面:macOS / Windows / Linux 桌面 JVM 应用;
  • Web:Wasm 目标。

在 KMP 基础上加 CMP 后,UI 层也可以共享(commonMain 写 Composable,各端只保留入口与平台配置)。判断是否值得:

信号倾向
需要两端观感都「像素级一致」的自定义 UICMP
产品有桌面 / Web 多端诉求,想一份 UI 通吃CMP
iOS 体验要深度贴合平台(手势、动效、系统组件习惯)原生 UI(SwiftUI + 共享逻辑 KMP)
UI 形态以列表 / 表单 / 内容为主,品牌一致性优先CMP 或原生皆可,按团队定
团队对 iOS 原生开发已很熟原生 UI 更稳

CMP 不是「RN 的 Kotlin 版」:它不是用 WebView 或解释器跑 UI,而是 Compose 描述 UI 后由各自平台的渲染层绘制;但同时也要接受「共享 UI = 平台观感折中」,系统级细节(如 iOS 原生滚动回弹、导航过渡)仍可能需要逐端调或写平台分支。

常见坑速查

现象对策
期待 KMP 共享 UI,没上 CMP双端 UI 仍写两遍,以为选错了先明确「共享逻辑层」与「共享 UI 层」是两档(CMP 才共享 UI)
iOS 只配真机 target模拟器链接失败 / 跑不起来iosSimulatorArm64(或 x86_64 旧机器)与真机都要配
忘加 plugin.serialization@Serializable 报错序列化编译器插件与 KMP 插件同版本引入
Ktor 只加 core 没加引擎构建通过但请求抛「找不到引擎」Android 加 OkHttp、iOS 加 Darwin、桌面/共用加 CIO 等
iOS framework 集成链路过长改了共享代码不生效,排查半天自动化生成脚本,改代码后一键重建;或选 CMP 工程形态
共享层放顶层可变状态iOS 上偶发崩溃 / 数据错乱新内存模型下不跨线程共享可变对象,用单向数据流
在 Swift 里直接 collect Flow编译不过 / 行为不符合预期用 AsyncStream 或 SKIE 桥接
expect/actual 到处自造平台差异代码散落,难以维护优先用官方多平台库,把差异收敛到少数封装点
CMP 当 RN 用,期待动态热更更新链路不符预期先理解 CMP 是编译期原生 UI,发布走正常 App 审核链路
忽略 UI 层两端折中iOS 用户觉得「不够 iOS」提前定视觉与交互基线,逐端打磨系统细节

检查清单

  • [ ] 明确共享范围:逻辑层共享、UI 层是否走 CMP,结论写进方案;
  • [ ] Android 与 iOS 目标、模拟器架构都在 Gradle 里配全;
  • [ ] 网络 / 序列化 / 存储 / DI 依赖的引擎在各端源集都配好;
  • [ ] 共享层遵守「不可变模型 + 单向数据流」,无顶层可变全局态;
  • [ ] iOS 集成链路(framework 生成、嵌入 Xcode)脚本化,改动可复现;
  • [ ] Swift 调 suspend / Flow 的桥接方案明确(async / AsyncStream / SKIE);
  • [ ] 评估过 CMP 与原生 UI 的观感基线,两端一致性预期对齐;
  • [ ] 排了 Kotlin / KMP / CMP 的升级预算,跟随官方路线图。

相关链接:客户端开发索引 · 技术全景与选型 · Android 开发 · Flutter · React Native · 桌面应用 · 鸿蒙开发。本页 Gradle / iOS 集成示例基于 2026 年当前工具链语境编写,需在 Android Studio + Xcode 环境中验证。

基于 VitePress 构建 · 内容以知识共享方式沉淀