最可靠的方式是通过 sourcesets 按平台分组声明依赖,因为 kmp 不支持在 dependencies 顶层直接写平台相关依赖;必须将依赖添加到对应平台 source set(如 androidmain、iosx64main)的 dependencies 块中,commonmain 放跨平台库,各平台 main 放原生依赖,并推荐使用 version catalog 统一管理版本。

用 sourceSets 按平台分组声明依赖最可靠
Gradle Kotlin Multiplatform(KMP)不支持在 dependencies 块顶层直接写平台相关依赖,必须通过 sourceSets 显式指定。否则会报错 Cannot add dependency to configuration 'commonMainImplementation' because it's not declared in the project 或构建时找不到符号。
核心逻辑是:每个平台对应一个 source set(如 androidMain、iosX64Main、jvmMain),你得把依赖加到对应 source set 的配置里,而不是笼统地塞进 implementation。
-
commonMain:放所有平台共用的 Kotlin 代码和跨平台库(如ktor-client-core、serialization-core) -
androidMain:仅 Android 平台可用的依赖(如androidx.core:core-ktx、okhttp) -
iosX64Main/iosArm64Main:iOS 平台原生依赖(如ktor-client-darwin) -
jvmMain:JVM 后端或桌面应用专用(如logback-classic、h2)
示例(build.gradle.kts 片段):
kotlin {
jvm()
androidTarget()
iosX64()
iosArm64()
sourceSets {
val commonMain by getting {
dependencies {
implementation(libs.ktor.client.core)
implementation(libs.kotlinx.serialization.json)
}
}
val androidMain by getting {
dependencies {
implementation(libs.ktor.client.android)
implementation(libs.okhttp)
}
}
val iosX64Main by getting {
dependsOn(commonMain)
dependencies {
implementation(libs.ktor.client.darwin)
}
}
}
}
别在 android 块里配 KMP 依赖
如果你用了 com.android.kotlin.multiplatform.library 插件(AGP 9.0+ 推荐方式),android 块只用于配置 Android 目标参数(如 minSdk、targetSdk),**不能**在里面写 dependencies —— 那里压根没有 implementation 函数,写了会直接编译失败。
常见错误写法:
android {
namespace = "com.example.lib"
compileSdk = 34
// ❌ 错误:这里不是放依赖的地方
dependencies {
implementation("androidx.core:core-ktx:1.12.0")
}
}
正确做法是回到 kotlin.sourceSets.androidMain.dependencies 中声明,或者用 androidMain 的 implementation(注意不是顶层 dependencies)。
用 Version Catalog + libs 避免硬编码版本号
多平台项目里,同一库不同平台的 artifact 往往版本一致但坐标不同(比如 ktor-client-android vs ktor-client-darwin),靠手写容易漏配或版本不一致。推荐用 gradle/libs.versions.toml 统一管理:
[libraries]
ktor-client-core = { module = "io.ktor:ktor-client-core", version.ref = "ktor" }
ktor-client-android = { module = "io.ktor:ktor-client-android", version.ref = "ktor" }
ktor-client-darwin = { module = "io.ktor:ktor-client-darwin", version.ref = "ktor" }
[versions]
ktor = "2.3.7"
这样在 sourceSets 里就能复用 libs.ktor.client.android,改一个地方全平台同步更新,也避免拼错 artifact ID。
注意 api 和 implementation 在 sourceSet 层级的意义
在 sourceSets 内部,api 表示该依赖会传递给依赖当前 source set 的其他 source set(比如 androidMain.api 的东西,androidTest 能访问);implementation 则仅限本 source set 使用。
容易踩的坑:
- 把
commonMain.api写成implementation→ 子平台 source set 无法 import 公共 API 类 - 在
androidMain里用api引入 Android 特有类 → iOS 编译时报 “unresolved reference” - 混淆
api和compileOnly:后者只参与编译,不打包进产物,适合注解处理器(如kotlinx-serialization-compiler-plugin)
实际中,commonMain 多用 api 暴露公共接口,各平台 Main 用 implementation 引入实现细节。
真正难的是跨平台模块间依赖的 visibility 控制 —— 一个 shared:utils 模块暴露了 FileUtils,但它的 androidMain 实现里用了 Context,这时候 iOS 模块引用它就会编译失败。这种问题不会在 build 时立刻报错,而是等到调用方尝试访问具体平台类时才暴露,调试成本高。











