11.1.3 配置 Gradle 项目

原文链接: https://kotlinlang.org/docs/gradle-configure-project.html

11.1.3 配置 Gradle 项目

要用 Gradle 构建 Kotlin 项目,你需要在构建脚本文件 build.gradle(.kts) 中添加 Kotlin Gradle 插件,并在其中配置项目依赖。

注意: 要进一步了解构建脚本的内容,请访问探索构建脚本一节。

应用插件

要应用 Kotlin Gradle 插件,请使用 Gradle 插件 DSL 中的 plugins{} 块:

Kotlin

1
2
3
4
5
6
plugins {
    // 把 `<...>` 替换为适合你的目标环境的插件名称
    kotlin("<...>") version "2.4.20"
    // 例如,如果你的目标环境是 JVM:
    // kotlin("jvm") version "2.4.20"
}

Groovy

1
2
3
4
5
6
plugins {
    // 把 `<...>` 替换为适合你的目标环境的插件名称
    id 'org.jetbrains.kotlin.<...>' version '2.4.20'
    // 例如,如果你的目标环境是 JVM:
    // id 'org.jetbrains.kotlin.jvm' version '2.4.20'
}

注意: Kotlin Gradle 插件(KGP)与 Kotlin 采用相同的版本编号。

在配置项目时,请检查 Kotlin Gradle 插件(KGP)与可用 Gradle 版本之间的兼容性。下表中列出了 Gradle 和 Android Gradle 插件(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 |

**警告:***Kotlin 2.0.20–2.0.21 和 Kotlin 2.1.0–2.1.10 与最高到 8.6 的 Gradle 完全兼容。Gradle 8.7–8.10 版本也受支持,只有一个例外:如果你使用 Kotlin Multiplatform Gradle 插件,在多平台项目中调用 JVM 目标的 withJava() 函数时可能会看到弃用警告。更多信息请参阅默认创建的 Java 源集。

你也可以使用最高到最新版本的 Gradle 和 AGP 版本,但如果这样做,请记住你可能会遇到弃用警告,或者某些新功能可能无法正常工作。

例如,Kotlin Gradle 插件和 kotlin-multiplatform 插件 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 插件数据

默认情况下,Kotlin Gradle 插件把持久化的项目专用数据存储在项目根目录下的 .kotlin 目录中。

警告: 不要把 .kotlin 目录提交到版本控制中。例如,如果你使用 Git,请把 .kotlin 加入项目的 .gitignore 文件。

你可以在项目的 gradle.properties 文件中添加以下属性来配置这一行为:

| Gradle 属性 | 说明 |

| kotlin.project.persistent.dir | 配置项目级数据的存储位置。默认:<project-root-directory>/.kotlin | | kotlin.project.persistent.dir.gradle.disableWrite | 控制是否禁止把 Kotlin 数据写入 .gradle 目录(用于与较旧版本的 IDEA 保持向后兼容)。默认:false |

以 JVM 为目标

要以 JVM 为目标,请应用 Kotlin JVM 插件。

Kotlin

1
2
3
plugins {
    kotlin("jvm") version "2.4.20"
}

Groovy

1
2
3
plugins {
    id "org.jetbrains.kotlin.jvm" version "2.4.20"
}

该块中的 version 必须是字面量,并且不能从其他构建脚本中应用。

Kotlin 与 Java 源码

Kotlin 源码和 Java 源码可以存放在同一个目录中,也可以放在不同的目录中。

默认约定是使用不同的目录:

1
2
3
4
5
project
    - src
        - main (root)
            - kotlin
            - java

警告: 不要把 Java .java 文件存放在 src/*/kotlin 目录中,因为这些 .java 文件不会被编译。请改为使用 src/main/java。

如果你不使用默认约定,则应更新相应的 sourceSets 属性:

Kotlin

1
2
3
sourceSets.main {
    java.srcDirs("src/main/myJava", "src/main/myKotlin")
}

Groovy

1
2
3
4
sourceSets {
    main.kotlin.srcDirs += 'src/main/myKotlin'
    main.java.srcDirs += 'src/main/myJava'
}

在构建模块中,你可能有相互关联的编译任务,例如:

  • compileKotlin 和 compileJava
  • compileTestKotlin 和 compileTestJava

注意: main 和 test 源集的编译任务彼此不相关。

对于这类相关任务,Kotlin Gradle 插件会检查 JVM 目标兼容性。kotlin 扩展或任务中的 jvmTarget 属性与 java 扩展或任务中的 targetCompatibility 取值不同,就会导致 JVM 目标不兼容。例如:compileKotlin 任务的 jvmTarget=1.8,而 compileJava 任务的 targetCompatibility=15(或继承了该值)。

要在整个项目范围内配置该检查的行为,请在 gradle.properties 文件中把 kotlin.jvm.target.validation.mode 属性设置为:

  • error – 插件会让构建失败;这是 Gradle 8.0+ 项目的默认值。
  • warning – 插件会打印警告消息;这是低于 Gradle 8.0 的项目的默认值。
  • ignore – 插件跳过该检查,不产生任何消息。

你也可以在 build.gradle(.kts) 文件中按任务级别配置它:

Kotlin

1
2
3
tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinJvmCompile>().configureEach {
    jvmTargetValidationMode.set(org.jetbrains.kotlin.gradle.dsl.jvm.JvmTargetValidationMode.WARNING)
}

Groovy

1
2
3
tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinJvmCompile.class).configureEach {
    jvmTargetValidationMode = org.jetbrains.kotlin.gradle.dsl.jvm.JvmTargetValidationMode.WARNING
}

为避免 JVM 目标不兼容,请配置工具链,或手动对齐 JVM 版本。

目标不兼容时可能出现的问题

有两种手动为 Kotlin 和 Java 源集设置 JVM 目标的方式:

  • 通过设置 Java 工具链的隐式方式。
  • 通过在 kotlin 扩展或任务中设置 jvmTarget 属性,并在 java 扩展或任务中设置 targetCompatibility 的显式方式。

如果你出现以下情况,就会发生 JVM 目标不兼容:

  • 显式设置了不同的 jvmTarget 和 targetCompatibility 值。
  • 使用默认配置,而你的 JDK 不等于 1.8。

我们来考虑一种默认的 JVM 目标配置:你的构建脚本中只有 Kotlin JVM 插件,且没有针对 JVM 目标的其他设置:

Kotlin

1
2
3
plugins {
    kotlin("jvm") version "2.4.20"
}

Groovy

1
2
3
plugins {
    id "org.jetbrains.kotlin.jvm" version "2.4.20"
}

当构建脚本中没有关于 jvmTarget 值的显式信息时,其默认值为 null,编译器会把它转换为默认值 1.8。targetCompatibility 等于当前 Gradle 的 JDK 版本,也就是你的 JDK 版本(除非你使用 Java 工具链方式)。假设你的 JDK 版本是 17,那么你发布的库产物会声明自身兼容 JDK 17+:org.gradle.jvm.version=17,这是错误的。在这种情况下,即使字节码版本是 1.8,你也必须在主项目中使用 Java 17 才能添加这个库。配置工具链可以解决这个问题。

Gradle Java 工具链支持

警告: 给 Android 用户的一个提醒。要使用 Gradle 工具链支持,请使用 Android Gradle 插件(AGP)8.1.0-alpha09 或更高版本。Gradle Java 工具链支持从 AGP 7.4.0 起才可用。不过,由于这个问题,直到 8.1.0-alpha09 版本,AGP 才把 targetCompatibility 设置为与工具链的 JDK 一致。如果你使用低于 8.1.0-alpha09 的版本,需要通过 compileOptions 手动配置 targetCompatibility。请把占位符 <MAJOR_JDK_VERSION> 替换为你希望使用的 JDK 版本: kotlin android { compileOptions { sourceCompatibility = <MAJOR_JDK_VERSION> targetCompatibility = <MAJOR_JDK_VERSION> } }

Gradle 6.7 引入了 Java 工具链支持。使用这一特性,你可以:

  • 使用与 Gradle 不同的 JDK 和 JRE 来运行编译、测试和可执行文件。
  • 使用尚未发布的语言版本来编译和测试代码。

有了工具链支持,Gradle 可以自动检测本地 JDK,并安装 Gradle 构建所需的缺失 JDK。现在 Gradle 本身可以运行在任何 JDK 上,同时对依赖主 JDK 版本的任务仍然可以复用远程构建缓存特性。

Kotlin Gradle 插件为 Kotlin/JVM 编译任务支持 Java 工具链。JS 和 Native 任务不使用工具链。Kotlin 编译器始终运行在 Gradle 守护进程所使用的 JDK 上。Java 工具链会:

  • 设置可用于 JVM 目标的 -jdk-home 选项。
  • 在用户没有显式设置 jvmTarget 选项时,把 compilerOptions.jvmTarget 设置为该工具链的 JDK 版本。如果用户没有配置工具链,jvmTarget 字段使用默认值。进一步了解 JVM 目标兼容性。
  • 设置供所有 Java 编译、测试和 javadoc 任务使用的工具链。
  • 影响 kapt 工作进程运行在哪个 JDK 上。

使用以下代码来设置工具链。请把占位符 <MAJOR_JDK_VERSION> 替换为你希望使用的 JDK 版本:

Kotlin

1
2
3
4
5
6
7
8
9
kotlin {
    jvmToolchain {
        languageVersion.set(JavaLanguageVersion.of(<MAJOR_JDK_VERSION>))
    }
    // 或者更短的写法:
    jvmToolchain(<MAJOR_JDK_VERSION>)
    // 例如:
    jvmToolchain(17)
}

Groovy

1
2
3
4
5
6
7
8
9
kotlin {
    jvmToolchain {
        languageVersion = JavaLanguageVersion.of(<MAJOR_JDK_VERSION>)
    }
    // 或者更短的写法:
    jvmToolchain(<MAJOR_JDK_VERSION>)
    // 例如:
    jvmToolchain(17)
}

请注意,通过 kotlin 扩展设置工具链也会更新 Java 编译任务的工具链。

你可以通过 java 扩展设置工具链,Kotlin 编译任务会使用它:

Kotlin

1
2
3
4
5
java {
    toolchain {
        languageVersion.set(JavaLanguageVersion.of(<MAJOR_JDK_VERSION>))
    }
}

Groovy

1
2
3
4
5
java {
    toolchain {
        languageVersion = JavaLanguageVersion.of(<MAJOR_JDK_VERSION>)
    }
}

如果你使用 Gradle 8.0.2 或更高版本,还需要添加工具链解析器插件。这类插件管理从哪些仓库下载工具链。作为示例,请在 settings.gradle(.kts) 中添加以下插件:

Kotlin

1
2
3
plugins {
    id("org.gradle.toolchains.foojay-resolver-convention") version("1.0.0")
}

Groovy

1
2
3
plugins {
    id 'org.gradle.toolchains.foojay-resolver-convention' version '1.0.0'
}

请对照 Gradle 网站检查 foojay-resolver-convention 的版本是否与你的 Gradle 版本匹配。

注意: 要了解 Gradle 使用了哪个工具链,请以日志级别 --info运行 Gradle 构建,并在输出中找到以 [KOTLIN] Kotlin compilation 'jdkHome' argument: 开头的字符串。冒号后面的部分就是工具链中的 JDK 版本。

要为特定任务设置任意 JDK(甚至是本地 JDK),请使用 Task DSL。

进一步了解 Kotlin 插件中的 Gradle JVM 工具链支持。

使用 Task DSL 设置 JDK 版本

Task DSL 允许为任何实现了 UsesKotlinJavaToolchain 接口的任务设置任意 JDK 版本。目前这类任务有 KotlinCompile 和 KaptTask。如果你希望 Gradle 查找主 JDK 版本,请替换构建脚本中的 <MAJOR_JDK_VERSION> 占位符:

Kotlin

1
2
3
4
5
6
7
val service = project.extensions.getByType<JavaToolchainService>()
val customLauncher = service.launcherFor {
    languageVersion.set(JavaLanguageVersion.of(<MAJOR_JDK_VERSION>))
}
project.tasks.withType<UsesKotlinJavaToolchain>().configureEach {
    kotlinJavaToolchain.toolchain.use(customLauncher)
}

Groovy

1
2
3
4
5
6
7
JavaToolchainService service = project.getExtensions().getByType(JavaToolchainService.class)
Provider<JavaLauncher> customLauncher = service.launcherFor {
    it.languageVersion = JavaLanguageVersion.of(<MAJOR_JDK_VERSION>)
}
tasks.withType(UsesKotlinJavaToolchain::class).configureEach { task ->
    task.kotlinJavaToolchain.toolchain.use(customLauncher)
}

或者,你可以指定本地 JDK 的路径,并把占位符 <LOCAL_JDK_VERSION> 替换为该 JDK 版本:

1
2
3
4
5
6
tasks.withType<UsesKotlinJavaToolchain>().configureEach {
    kotlinJavaToolchain.jdk.use(
        "/path/to/local/jdk", // 填入你的 JDK 路径
        JavaVersion.<LOCAL_JDK_VERSION> // 例如 JavaVersion.17
    )
}

关联编译任务

你可以通过在一组编译之间建立这样的关系来_关联_它们:让一个编译使用另一个编译的输出。关联编译会在它们之间建立 internal 可见性。

Kotlin 编译器默认关联一些编译,例如每个目标的 test 和 main 编译。如果你需要表达某个自定义编译与另一个编译相关联,请创建自己的关联编译。

要让 IDE 支持关联编译以便推断源集之间的可见性,请在 build.gradle(.kts) 中添加以下代码:

Kotlin

1
2
3
val integrationTestCompilation = kotlin.target.compilations.create("integrationTest") {
    associateWith(kotlin.target.compilations.getByName("main"))
}

Groovy

1
2
3
4
5
integrationTestCompilation {
    kotlin.target.compilations.create("integrationTest") {
        associateWith(kotlin.target.compilations.getByName("main"))
    }
}

这里,integrationTest 编译与 main 编译相关联,从而可以从功能测试中访问 internal 对象。

在启用 Java 模块(JPMS)的情况下配置

要让 Kotlin Gradle 插件与 Java 模块配合工作,请在构建脚本中添加以下几行,并把 YOUR_MODULE_NAME 替换为对 JPMS 模块的引用,例如 org.company.module:

Kotlin

1
2
3
4
5
6
7
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

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
tasks.named("compileJava", JavaCompile.class) {
    // 把编译好的 Kotlin 类提供给 javac——Java/Kotlin 混合源码要正常工作就需要这样做
    FileCollection mainOutput = sourceSets["main"].output
    options.compilerArgumentProviders.add(new CommandLineArgumentProvider() {
        @Override
        Iterable<String> asArguments() {
            return ["--patch-module", "YOUR_MODULE_NAME=${mainOutput.asPath}"]
        }
    })
}

注意: 请像往常一样把 module-info.java 放入 src/main/java 目录。对于模块,Kotlin 文件中的包名应等于 module-info.java 中的包名,以避免出现 “package is empty or does not exist” 构建失败。

进一步了解:

其他细节

禁止在编译任务中使用产物

在少数情况下,你可能会遇到由循环依赖错误导致的构建失败。例如,当你有多个编译,其中一个编译可以看到另一个编译的所有 internal 声明,而生成的产物又依赖这两个编译任务的输出时:

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。该属性控制编译任务中对产物输入的使用,并据此决定是否创建任务依赖。

默认情况下,该属性被设置为 true,以跟踪任务依赖。如果你遇到循环依赖错误,可以禁用编译任务中对产物的使用,从而移除任务依赖并避免该错误。

要禁用编译任务中对产物的使用,请在 gradle.properties 文件中添加以下内容:

1
kotlin.build.archivesTaskOutputAsFriendModule=false

Kotlin/JVM 任务的惰性创建

从 Kotlin 1.8.20 开始,Kotlin Gradle 插件会注册所有任务,并且不会在 dry run 时配置它们。

编译任务 destinationDirectory 的非默认位置

如果你覆盖了 Kotlin/JVM KotlinJvmCompile/KotlinCompile 任务的 destinationDirectory 位置,请更新构建脚本。你需要在 JAR 文件中显式地把 sourceSets.main.kotlin.classesDirectories 添加到 sourceSets.main.outputs:

1
2
3
4
tasks.jar(type: Jar) {
    from sourceSets.main.outputs
    from sourceSets.main.kotlin.classesDirectories
}

以多平台为目标

面向多个平台的项目(称为多平台项目)需要 kotlin-multiplatform 插件。

kotlin-multiplatform 插件需要 Gradle 7.6.3 或更高版本。

Kotlin

1
2
3
plugins {
    kotlin("multiplatform") version "2.4.20"
}

Groovy

1
2
3
plugins {
    id 'org.jetbrains.kotlin.multiplatform' version '2.4.20'
}

进一步了解面向不同平台的 Kotlin Multiplatform 以及面向 iOS 和 Android 的 Kotlin Multiplatform。

以 Android 为目标

创建 Android 应用时建议使用 Android Studio。了解如何使用 Android Gradle 插件。

以 Web 为目标

Kotlin 通过 Kotlin Multiplatform 提供了两种 Web 开发方式:

  • 基于 JavaScript 的方式(使用 Kotlin/JS 编译器)
  • 基于 WebAssembly 的方式(使用 Kotlin/Wasm 编译器)

这两种方式都使用 Kotlin Multiplatform 插件,但支持不同的使用场景。下面的小节说明如何在 Gradle 构建中配置各个目标,以及何时使用它们。

以 JavaScript 为目标

如果你的目标是以下情况,请使用 Kotlin/JS:

  • 与 JavaScript/TypeScript 代码库共享业务逻辑
  • 用 Kotlin 构建不共享的 Web 应用

更多信息请参阅 Web 开发。

以 JavaScript 为目标时,请使用 kotlin-multiplatform 插件:

Kotlin

1
2
3
plugins {
    kotlin("multiplatform") version "2.4.20"
}

Groovy

1
2
3
plugins {
    id 'org.jetbrains.kotlin.multiplatform' version '2.4.20'
}

通过指定 JavaScript 目标应在浏览器中还是在 Node.js 环境中运行来配置它:

1
2
3
4
5
kotlin {
    js().browser { // 或者 js().nodejs
        /* ... */
    }
}

注意: 请参阅关于 JavaScript Gradle 配置的更多细节,并进一步了解搭建 Kotlin/JS 项目。

以 WebAssembly 为目标

如果你想在多个平台之间共享逻辑和 UI,请使用 Kotlin/Wasm。更多信息请参阅 Web 开发。

与 JavaScript 一样,以 WebAssembly(Wasm)为目标时请使用 kotlin-multiplatform 插件:

Kotlin

1
2
3
plugins {
    kotlin("multiplatform") version "2.4.20"
}

Groovy

1
2
3
plugins {
    id 'org.jetbrains.kotlin.multiplatform' version '2.4.20'
}

根据你的需求,你可以面向:

  • wasmJs:用于在浏览器或 Node.js 中运行
  • wasmWasi:用于在支持 WASI(WebAssembly 系统接口)的 Wasm 环境中运行,例如 Wasmtime、WasmEdge 等等。

为 Web 浏览器或 Node.js 配置 wasmJs 目标:

1
2
3
4
5
6
7
kotlin {
    wasmJs {
        browser { // 或者 nodejs
            /* ... */
        }
    }
}

对于 WASI 环境,请使用 Node.js 或 Wasmtime 配置 wasmWasi 目标:

1
2
3
4
5
6
7
kotlin {
    wasmWasi {
        nodejs { // 或者 wasmtime
            /* ... */
        }
    }
}

注意: 查看关于 Wasm 的 Gradle 配置的更多细节。

Web 目标的 Kotlin 与 Java 源码

KGP 只处理 Kotlin 文件,因此建议把 Kotlin 文件和 Java 文件分开存放(如果项目包含 Java 文件)。如果你没有把它们分开存放,请在 sourceSets{} 块中指定源文件夹:

Kotlin

1
2
3
4
5
kotlin {
    sourceSets["main"].apply {
        kotlin.srcDir("src/main/myKotlin")
    }
}

Groovy

1
2
3
4
5
kotlin {
    sourceSets {
        main.kotlin.srcDirs += 'src/main/myKotlin'
    }
}

使用 KotlinBasePlugin 接口触发配置操作

要在应用任何 Kotlin Gradle 插件(JVM、JS、Multiplatform、Native 等)时触发某些配置操作,请使用所有 Kotlin 插件都继承自的 KotlinBasePlugin 接口:

Kotlin

1
2
3
4
5
6
7
import org.jetbrains.kotlin.gradle.plugin.KotlinBasePlugin

// ...

project.plugins.withType<KotlinBasePlugin>() {
    // 在这里配置你的操作
}

Groovy

1
2
3
4
5
6
7
import org.jetbrains.kotlin.gradle.plugin.KotlinBasePlugin

// ...

project.plugins.withType(KotlinBasePlugin.class) {
    // 在这里配置你的操作
}

配置依赖

要添加对某个库的依赖,请在源集 DSL 的 dependencies{} 块中设置所需类型的依赖(例如 implementation)。

Kotlin

1
2
3
4
5
6
7
kotlin {
    sourceSets {
        commonMain.dependencies {
            implementation("com.example:my-library:1.0")
        }
    }
}

Groovy

1
2
3
4
5
6
7
8
9
kotlin {
    sourceSets {
        commonMain {
            dependencies {
                implementation 'com.example:my-library:1.0'
            }
        }
    }
}

在顶层配置依赖

实验性

在多平台项目中,你可以使用顶层的 dependencies {} 块来配置公共依赖。在这里声明的依赖,其行为等同于被添加到 commonMain 或 commonTest 源集。

要使用顶层 dependencies {} 块,请在该块之前添加 @OptIn(ExperimentalKotlinGradlePluginApi::class) 注解来选择启用:

Kotlin

1
2
3
4
5
6
kotlin {
    @OptIn(ExperimentalKotlinGradlePluginApi::class)
    dependencies {
        implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.11.0")
    }
}

Groovy

1
2
3
4
5
kotlin {
    dependencies {
        implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.11.0'
    }
}

请在相应目标的 sourceSets {} 块中添平台特有的依赖。

你可以在 YouTrack 上分享你对这一功能的反馈。

依赖类型

请根据你的需求选择依赖类型。

类型说明何时使用
api在编译期和运行时都使用,并会导出给库的使用方。如果当前模块的公共 API 中使用了某个依赖中的类型,请使用 api 依赖。
implementation在当前模块的编译期和运行时使用,但不会暴露给依赖当前模块的其他模块的编译过程。用于模块内部逻辑所需的依赖。如果某个模块是不发布的终端应用,请使用 implementation 依赖而不是 api 依赖。
compileOnly用于当前模块的编译,在运行时以及其他模块的编译中都不可用。用于那些在运行时由第三方实现提供的 API。
runtimeOnly在运行时可用,但在任何模块的编译期都不可见。

对标准库的依赖

对标准库(stdlib)的依赖会自动添加到每个源集。所使用的标准库版本与 Kotlin Gradle 插件的版本相同。

对于平台特有的源集,会使用该库相应的平台特有变体,而其余源集则会添加公共标准库。Kotlin Gradle 插件会根据你的 Gradle 构建脚本中的 compilerOptions.jvmTarget 编译器选项选择合适的 JVM 标准库。

如果你显式声明了标准库依赖(例如你需要不同的版本),Kotlin Gradle 插件不会覆盖它,也不会再添加第二个标准库。

如果你完全不需要标准库,可以在 gradle.properties 文件中添加以下 Gradle 属性:

kotlin.stdlib.default.dependency=false

传递依赖的版本对齐

从 Kotlin 标准库 1.9.20 版本起,Gradle 使用标准库中包含的元数据来自动对齐传递性的 kotlin-stdlib-jdk7 和 kotlin-stdlib-jdk8 依赖。

如果你为 1.8.0 – 1.9.10 之间的任何 Kotlin 标准库版本添加依赖,例如:implementation("org.jetbrains.kotlin:kotlin-stdlib:1.8.0"),那么 Kotlin Gradle 插件会对传递性的 kotlin-stdlib-jdk7 和 kotlin-stdlib-jdk8 依赖使用这个 Kotlin 版本。这可以避免不同标准库版本导致的类重复。进一步了解把 kotlin-stdlib-jdk7 和 kotlin-stdlib-jdk8 合并到 kotlin-stdlib。你可以在 gradle.properties 文件中用 kotlin.stdlib.jdk.variants.version.alignment Gradle 属性禁用这一行为:

kotlin.stdlib.jdk.variants.version.alignment=false
其他对齐版本的方式
  • 如果你在版本对齐上遇到问题,可以通过 Kotlin BOM 对齐所有版本。在构建脚本中声明对 kotlin-bom 的平台依赖:

Kotlin

1
  implementation(platform("org.jetbrains.kotlin:kotlin-bom:2.4.20"))

Groovy

1
  implementation platform('org.jetbrains.kotlin:kotlin-bom:2.4.20')
  • 如果你没有为某个标准库版本添加依赖,但你有两个不同的依赖分别传递引入了不同的旧版本 Kotlin 标准库,那么你可以显式要求这些传递库使用 2.4.20 版本:

Kotlin

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
  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

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
  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 插件,请把 Kotlin Gradle 插件更新到与标准库版本一致:

Kotlin

1
2
3
4
  plugins {
      // 把 `<...>` 替换为插件名
      kotlin("<...>") version "2.4.20"
  }

Groovy

1
2
3
4
  plugins {
      // 把 `<...>` 替换为插件名
      id "org.jetbrains.kotlin.<...>" version "2.4.20"
  }

Kotlin

1
2
3
4
5
  dependencies {
      implementation("com.example:lib:1.0") {
          exclude(group = "org.jetbrains.kotlin", module = "kotlin-stdlib")
      }
  }

Groovy

1
2
3
4
5
  dependencies {
      implementation("com.example:lib:1.0") {
          exclude group: "org.jetbrains.kotlin", module: "kotlin-stdlib"
      }
  }

设置对测试库的依赖

kotlin.test API 可用于在所有受支持的平台上测试 Kotlin 项目。请把 kotlin-test 依赖添加到 commonTest 源集,这样 Gradle 插件就能为每个测试源集推断出相应的测试依赖。

Kotlin/Native 目标不需要额外的测试依赖,kotlin.test API 的实现是内置的。

Kotlin

1
2
3
4
5
6
7
kotlin {
    sourceSets {
        commonTest.dependencies {
            implementation(kotlin("test")) // 这会自动引入所有平台依赖
        }
    }
}

Groovy

1
2
3
4
5
6
7
8
9
kotlin {
    sourceSets {
        commonTest {
            dependencies {
                implementation kotlin("test") // 这会自动引入所有平台依赖
            }
        }
    }
}

注意: 对 Kotlin 模块的依赖可以使用简写,例如用 kotlin(“test”) 表示 “org.jetbrains.kotlin:kotlin-test”。

你也可以在任何共享源集或平台特有源集中使用 kotlin-test 依赖。

kotlin-test 的 JVM 变体

对于 Kotlin/JVM,Gradle 默认使用 JUnit 4。因此,kotlin("test") 依赖会解析为 JUnit 4 对应的变体,即 kotlin-test-junit。

你可以在构建脚本的测试任务中调用 useJUnitPlatform() 或 useTestNG() 来选择 JUnit 5 或 TestNG。下面的示例针对 Kotlin Multiplatform 项目:

Kotlin

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
kotlin {
    jvm {
        testRuns["test"].executionTask.configure {
            useJUnitPlatform()
        }
    }
    sourceSets {
        commonTest.dependencies {
            implementation(kotlin("test"))
        }
    }
}

Groovy

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
kotlin {
    jvm {
        testRuns["test"].executionTask.configure {
            useJUnitPlatform()
        }
    }
    sourceSets {
        commonTest {
            dependencies {
                implementation kotlin("test")
            }
        }
    }
}

下面的示例针对 JVM 项目:

Kotlin

1
2
3
4
5
6
7
8
9
dependencies {
    testImplementation(kotlin("test"))
}

tasks {
    test {
        useTestNG()
    }
}

Groovy

1
2
3
4
5
6
7
dependencies {
    testImplementation 'org.jetbrains.kotlin:kotlin-test'
}

test {
    useTestNG()
}

了解如何在 JVM 上使用 JUnit 测试代码。

自动解析 JVM 变体有时会给你的配置带来问题。在这种情况下,你可以显式指定所需的框架,并通过在项目的 gradle.properties 文件中添加以下行来禁用自动解析:

1
kotlin.test.infer.jvm.variant=false

如果你在构建脚本中显式使用了 kotlin("test") 的某个变体,而项目构建因兼容性冲突而失败,请参阅兼容性指南中的这个 issue。

设置对 kotlinx 库的依赖

如果你使用多平台库并且需要依赖共享代码,请只在共享源集中设置一次依赖。使用该库的基础产物名,例如 kotlinx-coroutines-core 或 ktor-client-core:

Kotlin

1
2
3
4
5
6
7
kotlin {
    sourceSets {
        commonMain.dependencies {
            implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.11.0")
        }
    }
}

Groovy

1
2
3
4
5
6
7
8
9
kotlin {
    sourceSets {
        commonMain {
            dependencies {
                implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.11.0'
            }
        }
    }
}

如果你在平台特有的依赖中需要某个 kotlinx 库,仍然可以在相应的平台源集中使用该库的基础产物名:

Kotlin

1
2
3
4
5
6
7
kotlin {
    sourceSets {
        jvmMain.dependencies {
            implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.11.0")
        }
    }
}

Groovy

1
2
3
4
5
6
7
8
9
kotlin {
    sourceSets {
        jvmMain {
            dependencies {
                implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.11.0'
            }
        }
    }
}

声明仓库

你可以声明一个公开可用的仓库,以使用其中的开源依赖。在 repositories{} 块中设置仓库名称:

Kotlin

1
2
3
repositories {
    mavenCentral()
}

Groovy

1
2
3
repositories {
    mavenCentral()
}

常用的仓库有 Maven Central 和 Google 的 Maven 仓库。

警告: 如果你同时也使用 Maven 项目,我们建议不要添加 mavenLocal() 作为仓库,因为在 Gradle 和 Maven 项目之间切换时可能会遇到问题。如果你必须添加 mavenLocal() 仓库,请把它放在 repositories{} 块中的最后。更多信息请参阅 mavenLocal() 的使用场景。

如果你需要在多个子项目中声明相同的仓库,请在 settings.gradle(.kts) 文件的 dependencyResolutionManagement{} 块中集中声明这些仓库:

Kotlin

1
2
3
4
5
dependencyResolutionManagement {
    repositories {
        mavenCentral()
    }
}

Groovy

1
2
3
4
5
dependencyResolutionManagement {
    repositories {
        mavenCentral()
    }
}

子项目中声明的任何仓库都会覆盖集中声明的仓库。关于如何控制这一行为以及有哪些可用选项的更多信息,请参阅 Gradle 文档。

注册生成的源

实验性 - 通用

注册生成的源,以帮助 IDE、第三方插件和其他工具区分生成的代码与常规源文件。这有助于 IDE 等工具在 UI 中以不同方式高亮生成的代码,并在导入项目时触发生成任务。请使用 KotlinSourceSet 接口来注册生成的源。

要注册一个包含 Kotlin 文件的目录,请在 build.gradle.kts 文件中使用 SourceDirectorySet 类型的 generatedKotlin 属性。例如:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
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)

这个示例创建了一个新任务 generator,其输出目录为 "src/main/kotlinGen"。任务运行时,doLast {} 任务操作会在输出目录中创建一个 generated.kt 文件。最后,该示例把任务的输出注册为生成的源。

如果你正在开发 Gradle 插件,可以使用 allKotlinSources 属性来访问在 KotlinSourceSet.kotlin 和 KotlinSourceSet.generatedKotlin 属性中注册的所有源。

接下来做什么?

进一步了解: