# 配置 Gradle 项目 要 [Gradle](https://docs.gradle.org/current/userguide/userguide.html) 使用来构建 Kotlin 项目, 你需要向你的构建脚本文件 `build.gradle(.kts)` [添加 Kotlin Gradle plugin](#apply-the-plugin), 并在构建脚本文件中 [配置项目的依赖项](#configure-dependencies). > **Note:** > 关于构建脚本, 更多内容请参见 [查看构建脚本](get-started-with-jvm-gradle-project.html#explore-the-build-script) 小节. ## 应用(Apply) Kotlin Gradle Plugin 要应用(Apply) Kotlin Gradle plugin, 请使用 Gradle plugin DSL 的 [plugins{} 代码段](https://docs.gradle.org/current/userguide/plugins.html#sec:plugins_block): Kotlin: ```KOTLIN plugins { // 请将 `<...>` 替换为与你的编译目标环境匹配的 plugin 名称 kotlin("<...>") version "2.4.20" // 例如, 如果你的编译目标环境是 JVM: // kotlin("jvm") version "2.4.20" } ``` Groovy: ```GROOVY plugins { // 请将 `<...>` 替换为与你的编译目标环境匹配的 plugin 名称 id 'org.jetbrains.kotlin.<...>' version '2.4.20' // 例如, 如果你的编译目标环境是 JVM: // id 'org.jetbrains.kotlin.jvm' version '2.4.20' } ``` > **Note:** > Kotlin Gradle plugin (KGP) 和 Kotlin 的版本号一致. 配置你的项目时, 请检查 Kotlin Gradle plugin (KGP) 是否兼容于你的 Gradle 版本. 下表是, Kotlin 完全支持 的 Gradle 和 Android Gradle plugin (AGP) 最低和最高版本: | KGP 版本 | Gradle 最低和最高版本 | AGP 最低和最高版本 | | --- | --- | --- | | 2.4.20 | 7.6.3–9.7.0 | 8.5.2–9.3.1 | | 2.4.0-2.4.10 | 7.6.3–9.5.0 | 8.5.2–9.1.0 | | 2.3.20–2.3.21 | 7.6.3–9.3.0 | 8.2.2–9.0.0 | | 2.3.10 | 7.6.3–9.0.0 | 8.2.2–9.0.0 | | 2.3.0 | 7.6.3–9.0.0 | 8.2.2–8.13.0 | | 2.2.20–2.2.21 | 7.6.3–8.14 | 7.3.1–8.11.1 | | 2.2.0–2.2.10 | 7.6.3–8.14 | 7.3.1–8.10.0 | | 2.1.20–2.1.21 | 7.6.3–8.12.1 | 7.3.1–8.7.2 | | 2.1.0–2.1.10 | 7.6.3–8.10* | 7.3.1–8.7.2 | | 2.0.20–2.0.21 | 6.8.3–8.8* | 7.1.3–8.5 | | 2.0.0 | 6.8.3–8.5 | 7.1.3–8.3.1 | | 1.9.20–1.9.25 | 6.8.3–8.1.1 | 4.2.2–8.1.0 | > **Warning:** > Kotlin 2.0.20–2.0.21 和 Kotlin 2.1.0–2.1.10 完全兼容 Gradle 8.6 或以下版本. 也支持 Gradle 版本 8.7 到 8.10, 但有一个例外: 如果你使用 Kotlin Multiplatform Gradle plugin, 在你的跨平台项目中调用 JVM 编译目标中的 `withJava()` 函数时, 可能遇到废弃警告. 更多详情请参见 [默认创建的 Java 源代码集](multiplatform-compatibility-guide.html). 你也可以使用最新版本之前的 Gradle 和 AGP 版本, 但如果你这样做, 请注意, 你可能会遇到废弃警告, 或者某些新功能可能无法正常工作. 例如, Kotlin Gradle plugin 和 `kotlin-multiplatform` plugin 2.4.20 最低需要 Gradle 版本 7.6.3 才能编译你的项目. 类似的, 完全支持的最高版本是 9.7.0. 这个版本不包含已废弃的 Gradle 方法和属性, 并且支持目前所有的 Gradle 功能特性. ### 较早的 KGP 版本 | KGP 版本 | Gradle 最低和最高版本 | AGP 最低和最高版本 | | --- | --- | --- | | 1.9.0–1.9.10 | 6.8.3–7.6.0 | 4.2.2–7.4.0 | | 1.8.20–1.8.22 | 6.8.3–7.6.0 | 4.1.3–7.4.0 | | 1.8.0–1.8.11 | 6.8.3–7.3.3 | 4.1.3–7.2.1 | | 1.7.20–1.7.22 | 6.7.1–7.1.1 | 3.6.4–7.0.4 | | 1.7.0–1.7.10 | 6.7.1–7.0.2 | 3.4.3–7.0.2 | | 1.6.20–1.6.21 | 6.1.1–7.0.2 | 3.4.3–7.0.2 | ### Kotlin Gradle plugin 在项目中的数据 默认情况下, Kotlin Gradle plugin 会将项目相关的数据保存在项目根目录下的 `.kotlin` 目录中. > **Warning:** > 不要将 `.kotlin` 目录提交到版本控制系统. 例如, 如果你在使用 Git, 请将 `.kotlin` 添加到你的项目的 `.gitignore` 文件中. 你可以将以下属性添加到你的项目的 `gradle.properties` 文件, 配置这些行为: | Gradle 属性 | 解释 | | --- | --- | | `kotlin.project.persistent.dir` | 配置你的项目数据的保存位置. 默认值: `/.kotlin` | | `kotlin.project.persistent.dir.gradle.disableWrite` | 控制是否禁止将 Kotlin 数据写到 `.gradle` 目录 (为了与旧版本的 IDEA 保持向后兼容). 默认值: false | ## 编译到 JVM 平台 要编译到 JVM 平台, 需要应用 Kotlin JVM plugin. Kotlin: ```KOTLIN plugins { kotlin("jvm") version "2.4.20" } ``` Groovy: ```GROOVY plugins { id "org.jetbrains.kotlin.jvm" version "2.4.20" } ``` 在这段代码中, `version` 必须是写明的字面值, 不能通过其他编译脚本得到. ### Kotlin 源代码与 Java 源代码 Kotlin 源代码与 Java 源代码可以保存在相同的目录下, 也可以放在不同的目录下. 默认的约定是使用不同的目录: ```TEXT project - src - main (root) - kotlin - java ``` > **Warning:** > 不要将 Java 的 `.java` 文件放在 `src/*/kotlin` 目录中, 因为这样的 `.java` 文件不会被编译. > > > > 你应该改为放在 `src/main/java` 目录中. 如果不使用默认约定的文件夹结构, 那么需要修改相应的 `sourceSets` 属性: Kotlin: ```KOTLIN sourceSets.main { java.srcDirs("src/main/myJava", "src/main/myKotlin") } ``` Groovy: ```GROOVY sourceSets { main.kotlin.srcDirs += 'src/main/myKotlin' main.java.srcDirs += 'src/main/myJava' } ``` ### 对相关联的编译任务检查 JVM 编译目标的兼容性 在构建模块中, 你可能会有多个相互关联的编译任务, 比如: * `compileKotlin` 与 `compileJava` * `compileTestKotlin` 与 `compileTestJava` > **Note:** > `main` 与 `test` 源代码集的编译任务之间没有关联. 对于这种相互关联的编译任务, Kotlin Gradle plugin 会检查 JVM 编译目标的兼容性. `kotlin` 扩展或任务中的 [jvmTarget 属性](gradle-compiler-options.html#attributes-specific-to-jvm) 和 `java` 扩展或任务中的 [targetCompatibility](https://docs.gradle.org/current/userguide/java_plugin.html#sec:java-extension) 如果设置为不同的值, 会导致 JVM 编译目标不兼容. 例如: `compileKotlin` 任务设置为 `jvmTarget=1.8`, 而 `compileJava` 任务设置为 (或 [继承得到](https://docs.gradle.org/current/userguide/java_plugin.html#sec:java-extension)) `targetCompatibility=15`. 要对整个项目的这个兼容性检查进行配置, 可以在 `gradle.properties` 文件中, 将 `kotlin.jvm.target.validation.mode` 属性设置为以下几个值: * `error` – plugin 会让构建失败; 对于 Gradle 8.0 以上版本, 这是项目的默认值. * `warning` – plugin 会输出警告信息; 对于低于 Gradle 8.0 的版本, 这是项目的默认值. * `ignore` – plugin 会跳过检查, 不输出任何警告信息. 你也可以在你的 `build.gradle(.kts)` 文件中对各个编译任务单独进行配置: Kotlin: ```KOTLIN tasks.withType().configureEach { jvmTargetValidationMode.set(org.jetbrains.kotlin.gradle.dsl.jvm.JvmTargetValidationMode.WARNING) } ``` Groovy: ```GROOVY tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinJvmCompile.class).configureEach { jvmTargetValidationMode = org.jetbrains.kotlin.gradle.dsl.jvm.JvmTargetValidationMode.WARNING } ``` 要避免 JVM 编译目标不兼容, 需要 [配置工具链](#gradle-java-toolchains-support), 或手动对齐(Align) JVM 版本. #### 如果编译目标之间不兼容, 会发生什么问题 有两种方式对 Kotlin 和 Java 源代码集手动设置 JVM 编译目标: * 隐含设定, 通过 [设置 Java 工具链](#gradle-java-toolchains-support) 来设置. * 明确设定, 通过设置 `kotlin` 扩展或任务中的 `jvmTarget` 属性, 以及`java` 扩展或任务中的 `targetCompatibility`. 如果你做以下设置, 就会发生 JVM 编译目标不兼容: * 对 `jvmTarget` 和 `targetCompatibility` 明确设置不同的版本. * 使用默认配置, 但你的 JDK 不等于 `1.8`. 如果在你的构建脚本中只有 Kotlin JVM plugin, 并且没有额外设置 JVM 编译目标, 我们来看看这时的默认 JVM 编译目标设置: Kotlin: ```KOTLIN plugins { kotlin("jvm") version "2.4.20" } ``` Groovy: ```GROOVY plugins { id "org.jetbrains.kotlin.jvm" version "2.4.20" } ``` 构建脚本中没有 `jvmTarget` 值的明确信息, 因此它的默认值为 `null`, 编译器将这个设置翻译为默认值 `1.8`. `targetCompatibility` 等于当前的 Gradle JDK 版本, 也就是你的 JDK 版本 (除非你使用 [Java 工具链策略](#gradle-java-toolchains-support)). 假设你的 JDK 版本是 `17`, 你发布的库文件会 [声明它兼容](https://docs.gradle.org/current/userguide/publishing_gradle_module_metadata.html) 于 JDK 17 以上版本: `org.gradle.jvm.version=17`, 实际上是错误的. 这种情况下, 在你的主项目中, 会需要使用 Java 17 才能添加这个库, 尽管它的字节码版本其实是 `1.8`. 请 [配置工具链](#gradle-java-toolchains-support) 来解决这个问题. ### Gradle Java 工具链支持 > **Warning:** > 给 Android 使用者的警告. 要使用 Gradle 工具链支持, 需要使用 Android Gradle plugin (AGP) 的 8.1.0-alpha09 或更高版本. > > > > Gradle Java 工具链支持只在 AGP 7.4.0 以上版本 [可用](https://issuetracker.google.com/issues/194113162). 但是, 由于 [这个问题](https://issuetracker.google.com/issues/260059413), AGP 8.1.0-alpha09 以前的版本没有将 `targetCompatibility` 设置为等于工具链的 JDK. 如果你在使用低于 8.1.0-alpha09 的版本, 你需要通过 `compileOptions` 来手动配置 `targetCompatibility`. 请将占位符 `` 替换为你想要使用的 JDK 版本: > > > > > ```KOTLIN > android { > compileOptions { > sourceCompatibility = > targetCompatibility = > } > } > ``` Gradle 6.7 引入了 [Java 工具链支持](https://docs.gradle.org/current/userguide/toolchains.html). 通过这个功能, 你可以: * 使用与 Gradle 不同的 JDK 和 JRE 来运行编译, 测试, 以及可执行程序. * 使用还未发布的语言版本编译和测试代码. 通过工具链支持, Gradle 能够自动查找本地的 JDK, 还能安装 Gradle 运行构建时需要的 JDK. 目前 Gradle 自身能够在任何 JDK 上运行, 而且还对依赖于主要 JDK 版本的任务重用 [远程构建缓存功能](gradle-compilation-and-caches.html#gradle-build-cache-support). Kotlin Gradle plugin 对 Kotlin/JVM 编译任务支持 Java 工具链. JS 和 Native 任务则不会使用工具链. Kotlin 编译器永远会在运行 Gradle daemon 的 JDK 上运行. Java 工具链会: * 为 JVM 编译目标设置 [-jdk-home 选项](compiler-reference.html#jdk-home-path). * 如果用户没有明确设置 `jvmTarget` 选项, 则将 [compilerOptions.jvmTarget](gradle-compiler-options.html#attributes-specific-to-jvm) 设置为工具链的 JDK 版本. 如果用户没有配置工具链, 那么 `jvmTarget` 会使用默认值. 详情请参见 [JVM 编译目标兼容性](#check-for-jvm-target-compatibility-of-related-compile-tasks). * 设置由任何 Java compile, test, 以及 javadoc 任务使用的工具链. * 影响 [kapt 任务执行器](kapt.html#run-kapt-tasks-in-parallel) 使用哪个 JDK. 可以使用以下代码来设置工具链. 请将占位符 `` 替换为你想要使用的 JDK 版本: Kotlin: ```KOTLIN kotlin { jvmToolchain { languageVersion.set(JavaLanguageVersion.of()) } // 或者使用更简短的写法: jvmToolchain() // 例如: jvmToolchain(17) } ``` Groovy: ```GROOVY kotlin { jvmToolchain { languageVersion = JavaLanguageVersion.of() } // 或者使用更简短的写法: jvmToolchain() // 例如: jvmToolchain(17) } ``` 注意, 如果使用 `kotlin` 扩展设置工具链, 也会改变 Java 编译任务的工具链. 你可以通过 `java` 扩展设置工具链, Kotlin 编译任务会使用这个设置: Kotlin: ```KOTLIN java { toolchain { languageVersion.set(JavaLanguageVersion.of()) } } ``` Groovy: ```GROOVY java { toolchain { languageVersion = JavaLanguageVersion.of() } } ``` 如果你使用 Gradle 8.0.2 或更高版本, 你还需要添加一个 [工具链解析器 plugin](https://docs.gradle.org/current/userguide/toolchains.html#sub:download_repositories). 这种 plugin 会管理从哪个仓库下载工具链. 例如, 向你的 `settings.gradle(.kts)` 文件添加以下 plugin: Kotlin: ```KOTLIN plugins { id("org.gradle.toolchains.foojay-resolver-convention") version("1.0.0") } ``` Groovy: ```GROOVY plugins { id 'org.gradle.toolchains.foojay-resolver-convention' version '1.0.0' } ``` 关于与你的 Gradle 版本对应的 `foojay-resolver-convention` 版本, 请参见 [Gradle 网站](https://docs.gradle.org/current/userguide/toolchains.html#sub:download_repositories). > **Note:** > 要确认 Gradle 使用哪个工具链, 请使用 [log 级别 --info](https://docs.gradle.org/current/userguide/logging.html#sec:choosing_a_log_level) 来运行你的 Gradle 构建, 并在输出中查找 `[KOTLIN] Kotlin compilation 'jdkHome' argument:` 开头的字符串. 冒号之后的部分就是工具链使用的 JDK 版本. 要为特定的 Task 设置任意的 JDK (甚至本地 JDK), 请使用 [Task DSL](#set-jdk-version-with-the-task-dsl). 详情请参见 [Kotlin plugin 中对 Gradle JVM 工具链的支持](https://blog.jetbrains.com/kotlin/2021/11/gradle-jvm-toolchain-support-in-the-kotlin-plugin/). ### 使用 Task DSL 设置 JDK 版本 Task DSL 可以对任何实现了 `UsesKotlinJavaToolchain` 接口的任务, 设置任意的 JDK 版本. 目前, 这些任务只有 `KotlinCompile` 和 `KaptTask`. 如果希望 Gradle 搜索主要的 JDK 版本, 请在你的构建脚本中替换 `` 占位符: Kotlin: ```KOTLIN val service = project.extensions.getByType() val customLauncher = service.launcherFor { languageVersion.set(JavaLanguageVersion.of()) } project.tasks.withType().configureEach { kotlinJavaToolchain.toolchain.use(customLauncher) } ``` Groovy: ```GROOVY JavaToolchainService service = project.getExtensions().getByType(JavaToolchainService.class) Provider customLauncher = service.launcherFor { it.languageVersion = JavaLanguageVersion.of() } tasks.withType(UsesKotlinJavaToolchain::class).configureEach { task -> task.kotlinJavaToolchain.toolchain.use(customLauncher) } ``` 或者你特也可以指定你的本地 JDK 路径, 然后使用这个 JDK 版本替换 `` 占位符: ```KOTLIN tasks.withType().configureEach { kotlinJavaToolchain.jdk.use( "/path/to/local/jdk", // 这里设置你的 JDK 路径 JavaVersion. // 例如, JavaVersion.17 ) } ``` ### 关联编译器任务 你可以将编译任务 关联(Associate) 在一起, 方法是在编译任务之间设置关联关系, 一个编译需要使用另一个编译的输出. 关联编译器任务会在编译任务之间建立 `internal` 的可见度. Kotlin 编译器会默认的关联某些编译任务, 比如每个编译目标的 `test` 和 `main` 编译任务. 如果你需要表达你的某个自定义编译任务与其它编译任务相关联, 请创建你自己的编译任务关联. 要让 IDE 支持关联编译任务, 在源代码集之间推断可见度, 请向你的 `build.gradle(.kts)` 添加以下代码: Kotlin: ```KOTLIN val integrationTestCompilation = kotlin.target.compilations.create("integrationTest") { associateWith(kotlin.target.compilations.getByName("main")) } ``` Groovy: ```GROOVY integrationTestCompilation { kotlin.target.compilations.create("integrationTest") { associateWith(kotlin.target.compilations.getByName("main")) } } ``` 在这个例子中, `integrationTest` 编译任务关联到 `main` 编译任务, 可以在功能测试(集成测试)代码中访问 `internal` 对象. ### Java Modules (JPMS) 启用时的配置 要让 Kotlin Gradle plugin 与 [Java 模块(Module)](https://dev.java/learn/modules/) 共同工作, 请向你的构建脚本添加以下内容, 并将其中的 `YOUR_MODULE_NAME` 替换为你的 JPMS 模块的引用, 例如, `org.company.module`: Kotlin: ```KOTLIN tasks.named("compileJava", JavaCompile::class.java) { // 将编译后的 Kotlin 类提供给 javac – 需要这样做才能让 Java/Kotlin 混合源代码正常工作 val mainOutput: FileCollection = sourceSets["main"].output options.compilerArgumentProviders.add(CommandLineArgumentProvider { listOf("--patch-module", "YOUR_MODULE_NAME=${mainOutput.asPath}") }) } ``` Groovy: ```GROOVY tasks.named("compileJava", JavaCompile.class) { // 将编译后的 Kotlin 类提供给 javac – 需要这样做才能让 Java/Kotlin 混合源代码正常工作 FileCollection mainOutput = sourceSets["main"].output options.compilerArgumentProviders.add(new CommandLineArgumentProvider() { @Override Iterable asArguments() { return ["--patch-module", "YOUR_MODULE_NAME=${mainOutput.asPath}"] } }) } ``` > **Note:** > 和通常一样, 请将 `module-info.java` 文件放在 `src/main/java` 目录内. > > > > 对于模块, Kotlin 文件中的包名称应该等于 `module-info.java` 中的包名称, 否则会出现构建错误 "package is empty or does not exist". 更多详情请参见: * [为 Java 模块系统构建模块](https://docs.gradle.org/current/userguide/java_library_plugin.html#sec:java_library_modular) * [使用 Java 模块系统构建应用程序](https://docs.gradle.org/current/userguide/application_plugin.html#sec:application_modular) * ["module" 在 Kotlin 中的意义](visibility-modifiers.html#modules) ### 其他细节 #### 在编译任务中禁用 artifact 在某些罕见的情况下, 你可能会遇到循环依赖错误导致的构建失败. 例如, 你有多个编译任务, 其中一个可以看到另一个的所有内部声明, 并且生成的 artifact 依赖于两个编译任务的输出: ``` FAILURE: Build failed with an exception. What went wrong: Circular dependency between the following tasks: :lib:compileKotlinJvm --- :lib:jvmJar \--- :lib:compileKotlinJvm (*) (*) - details omitted (listed previously) ``` 要修复这样的循环依赖错误, 我们添加了一个 Gradle 属性: `archivesTaskOutputAsFriendModule`. 这个属性控制在编译任务中是否使用 artifact 作为输入, 并因此决定是否创建任务之间的依赖. 默认情况下, 这个属性设置为 `true`, 追踪任务之间的依赖. 如果你遇到了循环依赖错误, 你可以在编译任务中禁用 artifact, 删除任务之间的依赖, 以避免循环依赖错误. 要在编译任务中禁用 artifact, 请向你的 `gradle.properties` 文件添加以下内容: ```PROPERTIES kotlin.build.archivesTaskOutputAsFriendModule=false ``` #### Kotlin/JVM 编译任务的延迟创建 从 Kotlin 1.8.20 开始, Kotlin Gradle plugin 在试运行(dry run)时会注册所有的编译任务, 但不对它们进行配置. #### 如果编译任务的输出目录不是默认位置 如果你覆盖了 Kotlin/JVM `KotlinJvmCompile`/`KotlinCompile` 编译任务的 `destinationDirectory` 位置, 请更新你的构建脚本. 在你的 JAR 文件中, 除 `sourceSets.main.outputs` 之外, 你需要明确添加 `sourceSets.main.kotlin.classesDirectories`: ```KOTLIN tasks.jar(type: Jar) { from sourceSets.main.outputs from sourceSets.main.kotlin.classesDirectories } ``` ## 编译到多个目标平台 编译到 [多个目标平台](multiplatform-dsl-reference.html#targets) 的项目, 称为 [跨平台项目](get-started.html), 需要使用 `kotlin-multiplatform` 插件. > **Note:** > `kotlin-multiplatform` 插件要求 Gradle 7.6.3 或更高版本. Kotlin: ```KOTLIN plugins { kotlin("multiplatform") version "2.4.20" } ``` Groovy: ```GROOVY plugins { id 'org.jetbrains.kotlin.multiplatform' version '2.4.20' } ``` 详情请参见 [在不同的平台使用 Kotlin Multiplatform](get-started.html) 和 [在 iOS 和 Android 平台使用 Kotlin Multiplatform](https://kotlinlang.org/docs/multiplatform/multiplatform-getting-started.html). ## 编译到 Android 平台 建议使用 Android Studio 来创建 Android 应用程序. 详情请参见 [如何使用 Android Gradle plugin](https://developer.android.com/studio/releases/gradle-plugin). ## 编译到 Web 平台 Kotlin 通过 Kotlin Multiplatform, 为 Web 开发提供两种方案: * 基于 JavaScript 的方案 (使用 Kotlin/JS 编译器) * 基于 WebAssembly 的方案 (使用 Kotlin/Wasm 编译器) 两种方案都使用 Kotlin Multiplatform plugin, 但支持不同的使用场景. 以下章节介绍如何在 Gradle 构建中配置每种编译目标, 以及何时使用它们. ### 编译到 JavaScript Kotlin/JS 适合于以下目标: * 与 JavaScript/TypeScript 代码库共用业务逻辑 * 使用 Kotlin 构建不可共用的 Web 应用程序 更多详情请参见 [Web 开发](web-overview.html#kotlin-js). 如果编译目标平台为 JavaScript, 请使用 `kotlin-multiplatform` plugin: Kotlin: ```KOTLIN plugins { kotlin("multiplatform") version "2.4.20" } ``` Groovy: ```GROOVY plugins { id 'org.jetbrains.kotlin.multiplatform' version '2.4.20' } ``` 指定在浏览器还是 Node.js 环境中运行, 配置 JavaScript 编译目标: ```KOTLIN kotlin { js().browser { // 或 js().nodejs /* ... */ } } ``` > **Note:** > 详情请参见 [针对 JavaScript 的 Gradle 配置详情](multiplatform-dsl-reference.html#web-targets), 以及 [如何设置 Kotlin/JS 项目](js-project-setup.html). ### 编译到 WebAssembly 如果你希望在多个平台之间共用逻辑和 UI, 请使用 Kotlin/Wasm. 更多详情请参见 [Web 开发](web-overview.html#kotlin-wasm). 与 JavaScript 一样, 编译目标为 WebAssembly (Wasm) 时, 也使用 `kotlin-multiplatform` plugin: Kotlin: ```KOTLIN plugins { kotlin("multiplatform") version "2.4.20" } ``` Groovy: ```GROOVY plugins { id 'org.jetbrains.kotlin.multiplatform' version '2.4.20' } ``` 根据你的需求, 可以选择以下编译目标: * `wasmJs`: 用于在浏览器或 Node.js 中运行 * `wasmWasi`: 用于在支持 [WASI (WebAssembly System Interface)](https://wasi.dev/) 的 Wasm 环境中运行, 例如 Wasmtime, WasmEdge, 等等. 对浏览器或 Node.js, 请配置 `wasmJs` 编译目标: ```KOTLIN kotlin { wasmJs { browser { // 或 nodejs /* ... */ } } } ``` 对于 WASI 环境, 请使用 Node.js 或 Wasmtime 配置 `wasmWasi` 编译目标: ```KOTLIN kotlin { wasmWasi { nodejs { // 或 wasmtime /* ... */ } } } ``` > **Note:** > 详情请参见 [针对 Wasm 的 Gradle 配置详情](multiplatform-dsl-reference.html#web-targets). ### Web 编译目标的 Kotlin 源代码与 Java 源代码 KGP 只能编译 Kotlin 源代码文件, 因此推荐将 Kotlin 和 Java 源代码文件放在不同的文件夹内(如果工程内包含 Java 文件的话). 如果不将源代码分开存放, 请在 `sourceSets{}` 代码段中指定源代码文件夹: Kotlin: ```KOTLIN kotlin { sourceSets["main"].apply { kotlin.srcDir("src/main/myKotlin") } } ``` Groovy: ```GROOVY kotlin { sourceSets { main.kotlin.srcDirs += 'src/main/myKotlin' } } ``` ## 使用 KotlinBasePlugin 接口触发配置动作 当任何 Kotlin Gradle plugin (JVM, JS, Multiplatform, Native, 等等) 被适用时, 要触发某些配置动作, 可以使用 `KotlinBasePlugin` 接口, 所有的 Kotlin plugin 都继承了这个接口: Kotlin: ```KOTLIN import org.jetbrains.kotlin.gradle.plugin.KotlinBasePlugin // ... project.plugins.withType() { // 在这里配置你的动作 } ``` Groovy: ```GROOVY import org.jetbrains.kotlin.gradle.plugin.KotlinBasePlugin // ... project.plugins.withType(KotlinBasePlugin.class) { // 在这里配置你的动作 } ``` ## 配置依赖项 如果要添加一个库的依赖, 需要在 source set DSL 中的 `dependencies{}` 代码段内, 设置必要 [类型](#dependency-types) 的依赖项 (比如, `implementation`). Kotlin: ```KOTLIN kotlin { sourceSets { commonMain.dependencies { implementation("com.example:my-library:1.0") } } } ``` Groovy: ```GROOVY kotlin { sourceSets { commonMain { dependencies { implementation 'com.example:my-library:1.0' } } } } ``` ### 在最顶层配置依赖项 你可以在跨平台项目中, 使用最顶层的 `dependencies {}` 代码块, 配置共通依赖项. 在这里声明的依赖项, 其行为相当于添加到 `commonMain` 或 `commonTest` 源代码集. 要使用最顶层的 `dependencies {}` 代码块, 请在代码块前添加 `@OptIn(ExperimentalKotlinGradlePluginApi::class)` 注解, 来表示使用者同意(Opt-in): Kotlin: ```KOTLIN kotlin { @OptIn(ExperimentalKotlinGradlePluginApi::class) dependencies { implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.11.0") } } ``` Groovy: ```GROOVY kotlin { dependencies { implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.11.0' } } ``` 在对应的编译目标的 `sourceSets {}` 代码块中, 添加平台相关的依赖项. 关于这个功能, 可以在 [YouTrack](https://youtrack.jetbrains.com/issue/KT-76446) 中分享你的反馈意见. ### 依赖项的类型 请根据你的需要选择依赖项的类型. | 类型 | 解释 | 使用场景 | | --- | --- | --- | | `api` | 编译期和运行期都会使用, 并导出给库的使用者. | 如果在当前模块的公开 API 中使用了一个依赖项中的任何类型, 请使用 `api` 依赖项. | | `implementation` | 对当前模块的编译期和运行期都会使用, 如果其他模块使用 `implementation` 依赖本模块, 那么对于其他模块的编译, 这个依赖项不会导出 | 对于模块的内部逻辑所需要的依赖项, 请使用这种类型. 如果一个模块是一个终端应用程序(endpoint application), 而且不对外公布(publish), 那么请使用 `implementation` 依赖项而不是 `api` 依赖项. | | `compileOnly` | 只用来编译当前模块, 在运行期不可用, 在编译其他模块时也不可用. | 如果 API 在运行时存在第三方的实现, 那么可以使用这种依赖项. | | `runtimeOnly` | 运行时可用, 但在任何模块的编译期都不可用. | | ### 对标准库的依赖项 对每个源代码集(Source Set), 会自动添加对标准库 (`stdlib`) 的依赖项. 使用的标准库版本与 Kotlin Gradle plugin 版本相同. 对于与平台相关的源代码集, 会使用针对这个平台的标准库, 同时, 对其他源代码集会添加共通的标准库. Kotlin Gradle plugin 会根据你的 Gradle 构建脚本的 `compilerOptions.jvmTarget` [编译器选项](gradle-compiler-options.html) 设置, 选择适当的 JVM 标准库. 如果明确的声明一个标准库依赖项(比如, 如果你需要使用不同的版本), Kotlin Gradle plugin 不会覆盖你的设置, 也不会添加第二个标准库. 如果你完全不需要标准库, 可以在你的 `gradle.properties` 文件中添加以下 Gradle 属性: ```PROPERTIES kotlin.stdlib.default.dependency=false ``` #### 传递依赖项的版本对齐 从 Kotlin 标准库 1.9.20 版开始, Gradle 使用包含在标准库中的元数据(metadata), 来自动对齐传递依赖项 `kotlin-stdlib-jdk7` 和 `kotlin-stdlib-jdk8` 的版本. 如果你添加了 Kotlin 标准库版本 1.8.0 到 1.9.10 之间的依赖项, 例如: `implementation("org.jetbrains.kotlin:kotlin-stdlib:1.8.0")`, 那么 Kotlin Gradle Plugin 会对传递依赖项 `kotlin-stdlib-jdk7` 和 `kotlin-stdlib-jdk8` 使用这个 Kotlin 版本. 这样会避免标准库的不同版本出现重复的类. 详情请参见 [kotlin-stdlib-jdk7 与 kotlin-stdlib-jdk8 合并到 kotlin-stdlib](whatsnew18.html#updated-jvm-compilation-target). 你可以在你的 `gradle.properties` 文件中使用 Gradle 属性 `kotlin.stdlib.jdk.variants.version.alignment` 来禁用这个动作: ```PROPERTIES kotlin.stdlib.jdk.variants.version.alignment=false ``` ##### 版本对齐的另一种方法 * 如果版本对齐出现了问题, 你可以使用 Kotlin [BOM](https://docs.gradle.org/current/userguide/platforms.html#sub:bom_import) 来对齐所有依赖项的版本. 在你的构建脚本中声明对 `kotlin-bom` 的平台依赖项: Kotlin: ```KOTLIN implementation(platform("org.jetbrains.kotlin:kotlin-bom:2.4.20")) ``` Groovy: ```GROOVY implementation platform('org.jetbrains.kotlin:kotlin-bom:2.4.20') ``` * 如果你没有添加某个版本的标准库的依赖项, 但你有两个不同的依赖项, 分别带来 Kotlin 标准库不同旧版本的传递依赖, 那么你可以对这些传递依赖的库明确指定 `2.4.20` 版本: Kotlin: ```KOTLIN dependencies { constraints { add("implementation", "org.jetbrains.kotlin:kotlin-stdlib-jdk7") { version { require("2.4.20") } } add("implementation", "org.jetbrains.kotlin:kotlin-stdlib-jdk8") { version { require("2.4.20") } } } } ``` Groovy: ```GROOVY dependencies { constraints { add("implementation", "org.jetbrains.kotlin:kotlin-stdlib-jdk7") { version { require("2.4.20") } } add("implementation", "org.jetbrains.kotlin:kotlin-stdlib-jdk8") { version { require("2.4.20") } } } } ``` * 如果你添加了 Kotlin 标准库 `2.4.20` 的依赖项: `implementation("org.jetbrains.kotlin:kotlin-stdlib:2.4.20")`, 并且使用了旧版本的 (低于 `1.8.0`) Kotlin Gradle plugin, 请更新 Kotlin Gradle plugin, 保持与标准库的版本一致: Kotlin: ```KOTLIN plugins { // 请将 `<...>` 替换为 plugin 名称 kotlin("<...>") version "2.4.20" } ``` Groovy: ```GROOVY plugins { // 请将 `<...>` 替换为 plugin 名称 id "org.jetbrains.kotlin.<...>" version "2.4.20" } ``` * 如果你使用旧版本 (低于 `1.8.0`) 的 `kotlin-stdlib-jdk7`/`kotlin-stdlib-jdk8`, 例如, `implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk7:SOME_OLD_KOTLIN_VERSION")`, 并且某个依赖项传递依赖到 `kotlin-stdlib:1.8+`, [请将你的 kotlin-stdlib-jdk<7/8>:SOME_OLD_KOTLIN_VERSION 替换为 kotlin-stdlib-jdk*:2.4.20](whatsnew18.html#updated-jvm-compilation-target), 或者在传递依赖它的库中 [排除(exclude)](https://docs.gradle.org/current/userguide/dependency_downgrade_and_exclude.html#sec:excluding-transitive-deps) `kotlin-stdlib:1.8+`: Kotlin: ```KOTLIN dependencies { implementation("com.example:lib:1.0") { exclude(group = "org.jetbrains.kotlin", module = "kotlin-stdlib") } } ``` Groovy: ```GROOVY dependencies { implementation("com.example:lib:1.0") { exclude group: "org.jetbrains.kotlin", module: "kotlin-stdlib" } } ``` ### 设置对测试库的依赖项 对于支持的所有平台, Kotlin 项目的测试可以使用 [kotlin.test](https://kotlinlang.org/api/latest/kotlin.test/) API. 对 `commonTest` 源代码集添加 `kotlin-test` 依赖项, 然后 Gradle plugin 会为每个测试源代码集推断出对应的测试库依赖项. Kotlin/Native 编译目标已经内建了 `kotlin.test` API 的实现, 不需要额外的测试依赖项. Kotlin: ```KOTLIN kotlin { sourceSets { commonTest.dependencies { implementation(kotlin("test")) // 这个设置会自动引入对应平台的所有依赖项 } } } ``` Groovy: ```GROOVY kotlin { sourceSets { commonTest { dependencies { implementation kotlin("test") // 这个设置会自动引入对应平台的所有依赖项 } } } } ``` > **Note:** > 对 Kotlin 模块的依赖项, 可以使用简写, 比如, 对 "org.jetbrains.kotlin:kotlin-test" 的依赖项可以简写为 kotlin("test"). 你也可以在任何共通源代码集或平台相关的源代码集中使用 `kotlin-test` 依赖项. #### kotlin-test 的 JVM 变体 对于 Kotlin/JVM, Gradle 默认使用 JUnit 4. 因此, `kotlin("test")` 依赖项会解析为 JUnit 4 的变体, 名为 `kotlin-test-junit`. 也可以选择使用 JUnit 5 或 TestNG, 方法是在构建脚本的测试任务中调用 [useJUnitPlatform()](https://docs.gradle.org/current/javadoc/org/gradle/api/tasks/testing/Test.html#useJUnitPlatform) 或 [useTestNG()](https://docs.gradle.org/current/javadoc/org/gradle/api/tasks/testing/Test.html#useTestNG). 下面是一个 Kotlin Multiplatform 项目的示例: Kotlin: ```KOTLIN kotlin { jvm { testRuns["test"].executionTask.configure { useJUnitPlatform() } } sourceSets { commonTest.dependencies { implementation(kotlin("test")) } } } ``` Groovy: ```GROOVY kotlin { jvm { testRuns["test"].executionTask.configure { useJUnitPlatform() } } sourceSets { commonTest { dependencies { implementation kotlin("test") } } } } ``` 下面是一个 JVM 项目的示例: Kotlin: ```KOTLIN dependencies { testImplementation(kotlin("test")) } tasks { test { useTestNG() } } ``` Groovy: ```GROOVY dependencies { testImplementation 'org.jetbrains.kotlin:kotlin-test' } test { useTestNG() } ``` 参见 [在 JVM 平台上如何使用 JUnit 测试代码](jvm-test-using-junit.html). JVM 变体的自动解析有时可能会对你的配置造成一些问题. 这种情况下, 你可以明确指定需要的框架, 并向项目的 `gradle.properties` 文件添加以下内容, 关闭自动解析: ```PROPERTIES kotlin.test.infer.jvm.variant=false ``` 如果你在构建脚本中明确使用了 `kotlin("test")` 的变体, 而且项目的构建脚本出现兼容性冲突问题, 不再正常工作, 请参见 [兼容性指南中的这个问题](compatibility-guide-15.html). ### 设置对 kotlinx 库的依赖项 如果你使用跨平台的库, 并且需要依赖共用代码, 那么只需要在共用源代码集中一次性设置依赖项. 请使用库的基本 artifact 名(base artifact name), 例如 `kotlinx-coroutines-core` 或 `ktor-client-core`: Kotlin: ```KOTLIN kotlin { sourceSets { commonMain.dependencies { implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.11.0") } } } ``` Groovy: ```GROOVY kotlin { sourceSets { commonMain { dependencies { implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.11.0' } } } } ``` 如果你需要一个 kotlinx 库的与平台相关的依赖项, 你仍然可以在对应的平台源代码集中使用库的基本 artifact 名(base artifact name): Kotlin: ```KOTLIN kotlin { sourceSets { jvmMain.dependencies { implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.11.0") } } } ``` Groovy: ```GROOVY kotlin { sourceSets { jvmMain { dependencies { implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.11.0' } } } } ``` ## 声明仓库 你可以声明一个可公开访问的仓库, 使用它的 open source 依赖项. 请在 `repositories{}` 代码段中, 设置仓库的名称: Kotlin: ```KOTLIN repositories { mavenCentral() } ``` Groovy: ```GROOVY repositories { mavenCentral() } ``` 常用的仓库是 [Maven Central](https://central.sonatype.com/) 和 [Google's Maven repository](https://maven.google.com/web/index.html). > **Warning:** > 如果你同时也在使用 Maven 项目, 我们建议不要将 `mavenLocal()` 添加为仓库, 因为在 Gradle 和 Maven 项目间切换时, 你可能遇到问题. 如果你一定需要添加 `mavenLocal()` 仓库, 请在你的 `repositories{}` 代码段中, 将它添加为最后一个仓库. 更多详情请参见 [使用 mavenLocal() 的情况](https://docs.gradle.org/current/userguide/declaring_repositories.html#sec:case-for-maven-local). 如果你需要在多个子项目中声明相同的仓库, 请在你的 `settings.gradle(.kts)` 文件中, 在 `dependencyResolutionManagement{}` 代码段中集中声明仓库: Kotlin: ```KOTLIN dependencyResolutionManagement { repositories { mavenCentral() } } ``` Groovy: ```GROOVY dependencyResolutionManagement { repositories { mavenCentral() } } ``` 在子项目中声明的任何仓库, 都会覆盖集中声明的仓库. 关于如何控制这种行为, 有什么解决办法, 详情请参见 [Gradle 的文档](https://docs.gradle.org/current/userguide/declaring_repositories.html#sub:centralized-repository-declaration). ## 注册生成的源代码 注册生成的源代码, 可以帮助 IDE, 第三方 plugin, 和其他工具区分生成的代码与普通的源代码文件. 这有助于 IDE 等工具在 UI 中以不同的方式高亮显示生成的代码, 以及在导入项目时触发生成任务. 请使用 [KotlinSourceSet](https://kotlinlang.org/api/kotlin-gradle-plugin/kotlin-gradle-plugin-api/org.jetbrains.kotlin.gradle.plugin/-kotlin-source-set/) 接口来注册生成的源代码. 要注册包含 Kotlin 文件的目录, 请在你的 `build.gradle.kts` 文件中, 使用 [generatedKotlin](https://kotlinlang.org/api/kotlin-gradle-plugin/kotlin-gradle-plugin-api/org.jetbrains.kotlin.gradle.plugin/-kotlin-source-set/generated-kotlin.html) 属性, 这个属性的类型为 [SourceDirectorySet](https://docs.gradle.org/current/kotlin-dsl/gradle/org.gradle.api.file/-source-directory-set/index.html). 例如: ```KOTLIN val generatorTask = project.tasks.register("generator") { val outputDirectory = project.layout.projectDirectory.dir("src/main/kotlinGen") outputs.dir(outputDirectory) doLast { outputDirectory.file("generated.kt").asFile.writeText( // language=kotlin """ fun printHello() { println("hello") } """.trimIndent() ) } } kotlin.sourceSets.getByName("main").generatedKotlin.srcDir(generatorTask) ``` 这个示例创建一个新的 task `generator`, 它的输出目录为 `"src/main/kotlinGen"`. task 运行时, `doLast {}` 动作会在输出目录中创建一个 `generated.kt` 文件. 最后, 这个示例将 task 的输出注册为生成的源代码. 如果你在开发 Gradle 插件, 可以使用 [allKotlinSources](https://kotlinlang.org/api/kotlin-gradle-plugin/kotlin-gradle-plugin-api/org.jetbrains.kotlin.gradle.plugin/-kotlin-source-set/all-kotlin-sources.html) 属性, 来访问在 [KotlinSourceSet.kotlin](https://kotlinlang.org/api/kotlin-gradle-plugin/kotlin-gradle-plugin-api/org.jetbrains.kotlin.gradle.plugin/-kotlin-source-set/kotlin.html) 和 `KotlinSourceSet.generatedKotlin` 属性中注册的所有源代码. ## 下一步做什么? 学习: * [编译器选项, 以及如何传递编译器选项](gradle-compiler-options.html). * [增量编译, 缓存, 构建报告, 以及 Kotlin Daemon](gradle-compilation-and-caches.html). * [Gradle 基本概念与详细信息](https://docs.gradle.org/current/userguide/userguide.html). * [对 Gradle plugin 变体的支持](gradle-plugin-variants.html).