在 Kotlin Multiplatform 项目中添加 JVM 目标需在启用 kotlin-multiplatform 插件后、kotlin { ... } 块内调用 jvm(),并手动配置 jvmMain 依赖(如 kotlin-stdlib-jdk8),因 jvm() 仅注册目标而不自动引入 JVM 特有库;同时须配 jvmToolchain 并与 jvmTarget 一致,Android 项目慎用 JDK 17+。

怎么在 Kotlin Multiplatform 项目中添加 JVM 目标
直接加 jvm() 就行,但必须在 kotlin-multiplatform 插件启用后、且在 targets DSL 内调用。KMP 的目标不是“开启开关”,而是显式声明一个 KotlinTarget 实例,否则 Gradle 根本不会生成对应源集或编译任务。
- 在模块级
build.gradle.kts(推荐)或build.gradle中,确保已应用org.jetbrains.kotlin.multiplatform插件 - 在
kotlin { ... }块内调用jvm(),不要放在android {}或其他插件块里 - 如果同时需要 Android 目标,
android()和jvm()可共存,但它们是独立目标,各自拥有main和test源集
示例(Kotlin DSL):
kotlin {
jvm()
android()
sourceSets {
commonMain.dependencies {
implementation("org.jetbrains.kotlin:kotlin-stdlib-common")
}
jvmMain.dependencies {
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
}
androidMain.dependencies {
implementation("org.jetbrains.kotlin:kotlin-stdlib")
}
}
}
为什么 jvm() 后还要手动配 jvmMain 依赖
因为 jvm() 只注册目标,不自动拉取 JVM 特有库。KMP 默认只给 commonMain 加 kotlin-stdlib-common,而 jvmMain 需要完整 JDK 支持(如 java.time、Files),所以必须显式指定 kotlin-stdlib-jdk8 或 kotlin-stdlib-jdk11 —— 这和 Android 模块里用 kotlin-stdlib 是两回事。
- 用
kotlin-stdlib-jdk11前,确认项目jvmTarget设为"11",否则字节码版本不匹配 - 不要在
commonMain里直接依赖kotlin-stdlib-jdk*,会触发编译错误:该库不含expect声明 - 若 JVM 目标仅用于测试(比如跑 JUnit),可只声明
jvmTest而不配jvmMain
常见报错:Cannot access 'kotlin.io' which is a member of external library
这通常是因为你在 commonMain 里用了 JVM/Android 特有的 API(比如 File、println),但没写 expect / actual。KMP 不允许跨平台代码直接调用平台专属类。
- 检查出错位置是否在
commonMain;如果是,把涉及 IO、线程、时间等操作改成expect fun声明 - 确认
jvmMain和androidMain都提供了对应actual实现,且签名完全一致(包括返回类型、参数名) - 注意:Kotlin 1.9+ 中
println已在common中声明为expect,但旧版仍需手动桥接
要不要配 jvmToolchain
要,尤其当团队使用不同 JDK 版本时。jvmToolchain 显式约束编译器使用的 JDK,比单纯设 jvmTarget 更可靠。它影响的是编译过程本身,而非仅字节码版本。
- 在
kotlin { ... }外层(即project级)配置,避免被子项目覆盖 - 写法:
java { toolchain { languageVersion.set(JavaLanguageVersion.of(11)) } } - 搭配
kotlinOptions.jvmTarget = "11"使用,二者必须一致,否则 Gradle 会警告并可能降级处理 - Android 项目慎用 JDK 17+ 的
jvmToolchain,AGP 8.4–9.0 对 JDK 17 支持尚不稳定,容易触发 D8 编译失败
最易被忽略的一点:JVM 目标一旦加入,gradle build 就会默认构建它,包括运行 jvmTest。如果没写测试却报 test task failed,先检查是不是 jvmTest 源集下残留了空目录或错误的 build.gradle 片段。











