配置 Kotlin Multiplatform 项目的 Compose 版本:共用依赖、平台差异、构建目标选择
当 Compose 进入 Kotlin Multiplatform (KMP) 项目,依赖管理需要同时处理 跨平台共享 与 平台特化 两个维度。本章从构建脚本结构出发,逐一拆解 commonMain 共用依赖、平台差异处理方式以及多目标构建的选择逻辑。
4.1 KMP 项目中的 Compose 依赖层次
KMP 项目目录通常按 commonMain、androidMain、desktopMain、iosMain 等源集组织。Compose 依赖并不完全平铺,而是分层铺设:
- commonMain:放置不依赖底层渲染的 API,如
compose.runtime、compose.foundation.layout、compose.material3(部分),以及自定义的expect声明。 - androidMain:补充 Android 平台 Compose 实现,如
compose.ui(Android 原生)、compose.material3的 Android 适配、Activity集成。 - desktopMain:使用
compose.desktop.currentOs系列依赖,包含窗口管理、鼠标事件等。 - iosMain:目前 Compose Multiplatform 通过 Skia 后端提供 iOS 支持,依赖
compose.ui(skiko 实现)。
共用依赖需要在 commonMain 的 dependencies 块中声明,而平台特定依赖则放在对应源集下。
4.2 共用依赖配置:commonMain 的核心声明
在 build.gradle.kts 的 kotlin.sourceSets.commonMain.dependencies 块内,列出所有跨平台 Compose 模块。典型配置:
kotlin {
sourceSets {
commonMain.dependencies {
implementation(compose.runtime)
implementation(compose.foundation)
implementation(compose.material3)
implementation(compose.components.resources)
// 如需使用 Compose 编译器注解(如 @Preview),需要显式添加:
implementation(compose.compiler)
}
}
}
compose.runtime、compose.foundation 等坐标来自 org.jetbrains.compose 插件。它们会自动使用插件声明的 Compose 编译器版本,无需手动指定 Kotlin Compose Plugin 版本。
共用依赖的版本号由 org.jetbrains.compose 插件统一管理,无需在每个依赖后填写版本。插件版本与 Kotlin 版本之间有严格兼容矩阵,详见第 2 章。
4.3 平台差异处理:expect/actual 与平台源码集
当同一 API 在不同平台有不同实现时,使用 expect 和 actual 机制。例如在 commonMain 中声明:
// commonMain
expect fun getPlatformName(): String
@Composable
expect fun PlatformSpecificText()
然后在 androidMain 和 desktopMain 分别提供 actual 实现。注意,actual 函数需要标注 @Composable(若原 expect 是 Composable 函数)。
平台特定依赖则直接写入对应源集的 dependencies 块:
androidMain.dependencies {
implementation(compose.ui) // Android 原生 UI
implementation(compose.material3) // Material3 Android 组件
implementation("androidx.activity:activity-compose:1.8.2")
}
desktopMain.dependencies {
implementation(compose.desktop.currentOs)
implementation(compose.material3) // Desktop 端 Material3
}
iosMain.dependencies {
implementation(compose.ui) // iOS Skiko 后端
implementation(compose.foundation)
}
4.4 构建目标选择
构建目标通过 kotlin.targets 块配置。以支持 Android、Desktop (JVM) 和 iOS 为例:
kotlin {
androidTarget {
compilations.all {
kotlinOptions {
jvmTarget = "17"
}
}
}
jvm("desktop") {
compilations.all {
kotlinOptions {
jvmTarget = "17"
}
}
}
iosX64()
iosArm64()
iosSimulatorArm64()
sourceSets { /* ...依赖声明... */ }
}
compose {
kotlinCompilerPlugin.set("1.5.12") // 显式指定 Compose 编译器版本(可选)
// 或使用插件默认版本
}
如需添加 Windows 或 Linux 桌面目标,可在 jvm("desktop") 之外再添加 linuxX64、mingwX64。每个平台都需要对应的 compose.desktop 模块支持。
compose.desktop.currentOs 与 compose.desktop.windows 等平台特定模块。currentOs 会自动根据构建主机选择对应后端,适合开发阶段;生产构建需要明确指定所有目标平台依赖。
4.5 完整示例:多平台 build.gradle.kts
以下是一个支持 Android、Desktop (JVM)、iOS 的 KMP + Compose 项目典型配置:
plugins {
kotlin("multiplatform") version "1.9.22"
id("org.jetbrains.compose") version "1.6.0"
}
kotlin {
androidTarget {
compilations.all { kotlinOptions.jvmTarget = "17" }
}
jvm("desktop") {
compilations.all { kotlinOptions.jvmTarget = "17" }
}
iosX64(); iosArm64(); iosSimulatorArm64()
sourceSets {
val commonMain by getting {
dependencies {
implementation(compose.runtime)
implementation(compose.foundation)
implementation(compose.material3)
implementation(compose.components.resources)
}
}
val androidMain by getting {
dependencies {
implementation(compose.ui)
implementation(compose.material3)
implementation("androidx.activity:activity-compose:1.8.2")
}
}
val desktopMain by getting {
dependencies {
implementation(compose.desktop.currentOs)
implementation(compose.material3)
}
}
val iosX64Main by getting
val iosArm64Main by getting
val iosSimulatorArm64Main by getting
val iosMain by creating {
dependsOn(commonMain)
iosX64Main.dependsOn(this)
iosArm64Main.dependsOn(this)
iosSimulatorArm64Main.dependsOn(this)
dependencies {
implementation(compose.ui)
implementation(compose.foundation)
}
}
}
}
compose {
// 可选:指定编译器版本,默认使用插件捆绑版本
// kotlinCompilerPlugin.set("1.5.12")
}
4.6 平台差异依赖速查表
| 依赖坐标(via compose.*) | commonMain | androidMain | desktopMain | iosMain |
|---|---|---|---|---|
compose.runtime |
✅ 必须 | 自动继承 | 自动继承 | 自动继承 |
compose.foundation |
✅ 推荐 | 自动继承 | 自动继承 | 自动继承 |
compose.material3 |
✅ 推荐 | ✅ 可额外添加 | ✅ 可额外添加 | ✅ 可额外添加 |
compose.ui |
❌ 不可(平台抽象) | ✅ 必须 | ✅ 必须 | ✅ 必须 |
compose.desktop.currentOs |
❌ | ❌ | ✅ 必须 | ❌ |
expect/actual 解决,不要试图在 commonMain 中引入 compose.ui 或桌面专属依赖。
4.7 常见错误与调试
- Missing source set:未正确创建
iosMain或desktopMain中间源集会引发编译错误。务必使用by creating并建立dependsOn(commonMain)。 - Compose compiler version mismatch:若手动设置了
compose.kotlinCompilerPlugin,必须确保其与 Kotlin 版本兼容(如 Kotlin 1.9.22 对应 Compose Compiler 1.5.12)。 - Desktop 目标找不到 compose.desktop.currentOs:检查是否添加了
compose.desktop.currentOs依赖,并确保jvm("desktop")目标名称与插件期望一致。 - iOS 构建失败:确认 Xcode 版本和 Kotlin/Native 工具链支持。iOS 目标可能需要显式指定
compose.ui版本与 macOS 后端一致。
4.8 版本锁定与冲突排查
当多个依赖间接引入不同版本的 Compose Compiler 时,可在 compose 块中强制指定:
compose {
kotlinCompilerPlugin.set("1.5.12")
// 等价于常规 Gradle 配置:kotlinCompilerExtensionVersion
}
若要禁用插件自动注入(罕见场景),可使用:
compose {
kotlinCompilerPlugin.set(null as String?)
// 此时需手动添加 compiler 依赖
}
建议始终让插件管理编译器版本,仅在出现编译报错 Compose Compiler requires Kotlin version X.Y.Z 时才手动覆盖。
commonMain 的 dependencies 中写 implementation("org.jetbrains.compose:compose-ui:1.6.0") 而非使用快捷坐标 compose.ui。这会导致版本不统一,且 Android 依赖也无法正确解析。务必使用 compose.* 快捷访问器,它们由插件自动映射到正确的 Maven 坐标。