2. KMP工程环境搭建
Kotlin Multiplatform(KMP)工程的环境搭建,本质上是把“一份 Kotlin 源码要编译到多个平台”这件事,翻译成 Gradle 能理解的插件、源集(source set)与目标(target)声明。理解这三者的关系,比记住某一条命令更重要:插件负责提供能力,Gradle 配置负责组织构建,目标声明负责决定产物落到哪些平台。本节以一个可运行的共享模块为例,走通从零初始化到多平台编译通过的全过程。
一、环境前置条件与版本对齐
KMP 对工具链版本较敏感,建议先固定三件套:JDK、Gradle、Kotlin。示例采用 JDK 17、Gradle 8.7、Kotlin 2.0.20,Android 侧使用 AGP 8.5.2。这些是示例参数,实际项目应以官方兼容矩阵为准。需要特别注意的是,Kotlin 2.0 之后 kotlin("multiplatform") 插件已内置对 Compose Multiplatform 的兼容支持,但 Compose 编译器插件仍需单独声明。
初始化方式有两种:一是用 IntelliJ IDEA / Android Studio 的 KMP 向导生成骨架;二是手动创建目录与构建脚本。向导适合快速起步,但生成的结构往往包含大量示例代码,不利于理解。下面采用手动方式,从空目录开始,这样每一行配置都有明确目的。
二、工程目录与源集结构
KMP 的核心概念是源集:commonMain 存放所有平台共享的代码,androidMain、iosMain、desktopMain 等存放平台特有实现。源集之间通过 dependsOn 形成继承关系,commonMain 是公共父源集。目录结构如下:
shared/
├── build.gradle.kts
└── src/
├── commonMain/kotlin/ # 共享业务逻辑
├── commonTest/kotlin/ # 共享测试
├── androidMain/kotlin/ # Android 平台实现
├── iosMain/kotlin/ # iOS 平台实现
└── desktopMain/kotlin/ # JVM 桌面实现
这个结构不是强制的,但遵循它可以让 Gradle 默认源集约定生效,减少显式配置。若自定义目录,需要在 kotlin { sourceSets { ... } } 中重写 kotlin.srcDir。
三、build.gradle.kts 关键配置
共享模块的构建脚本需要完成四件事:应用插件、声明目标、配置源集依赖、设置编译选项。以下为示例配置:
plugins {
kotlin("multiplatform") version "2.0.20"
id("com.android.library") version "8.5.2"
}
kotlin {
androidTarget {
compilations.all {
kotlinOptions.jvmTarget = "17"
}
}
jvm("desktop")
iosX64(); iosArm64(); iosSimulatorArm64()
sourceSets {
val commonMain by getting {
dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.1")
}
}
val commonTest by getting {
dependencies { implementation(kotlin("test")) }
}
val androidMain by getting
val desktopMain by getting
val iosMain by creating {
dependsOn(commonMain)
}
}
}
这里有几个容易踩坑的点。第一,iosMain 在部分版本中不会自动创建,需要显式 creating 并 dependsOn(commonMain);第二,androidTarget 必须配合 com.android.library 插件,否则 Android 目标无法解析;第三,JVM 目标用 jvm("desktop") 命名后,源集名变为 desktopMain,而不是默认的 jvmMain。
四、多目标平台声明与产物关系
目标声明决定了编译产物。Android 目标产出 AAR,JVM 目标产出 JAR,iOS 目标产出 klib 与最终 framework。下图展示了插件、Gradle 配置、源集与目标之间的依赖与产物关系,帮助建立整体认知:
五、初始化后的验证与常见问题
配置完成后,执行 ./gradlew :shared:tasks 查看可用任务。若能看到 compileKotlinAndroid、compileKotlinDesktop、compileKotlinIosArm64 等任务,说明目标声明已被正确解析。接着执行 ./gradlew :shared:build,观察是否所有目标都编译通过。
常见问题有三类。其一,iOS 目标在非 macOS 环境下无法编译,Windows/Linux 上应只保留 Android 与 JVM 目标,或使用 if (HostManager.hostIsMac) 条件声明;其二,commonMain 中引用了平台 API(如 java.util.UUID),会导致其他平台编译失败,应改用 expect/actual 或 kotlin.uuid.Uuid;其三,AGP 与 Kotlin 版本不匹配会报 Unsupported Kotlin plugin version,需对照兼容表调整。
gradle.properties 中开启 kotlin.mpp.enableCInteropCommonization=true 与 kotlin.native.cacheKind=none(调试期),可减少 iOS 编译缓存带来的困惑。六、可复用的初始化检查清单
为便于后续章节直接复用,下面给出一份初始化检查清单,覆盖从环境到验证的关键项:
| 检查项 | 期望结果 | 判断依据 |
|---|---|---|
| JDK 版本 | 17 或以上 | java -version 输出一致 |
| Gradle Wrapper | 8.7 | gradle/wrapper/gradle-wrapper.properties |
| KMP 插件 | 2.0.20 | plugins 块中版本号 |
| 目标声明 | android / desktop / ios | kotlin { } 中 target 数量 |
| 源集继承 | iosMain dependsOn commonMain | sourceSets 配置 |
| 编译验证 | BUILD SUCCESSFUL | ./gradlew :shared:build |