Android Gradle 插件 4.0 添加了对在 Gradle 构建配置中使用 Kotlin 的支持,以替代传统上在 Gradle 配置文件中使用的编程语言 Groovy。
与 Groovy 相比,Kotlin 更适合编写 Gradle 脚本,因为 Kotlin 可读性更好,并提供更好的编译时检查和 IDE 支持。
尽管与 Groovy 相比,Kotlin 目前在 Android Studio 的代码编辑器中提供了更好的集成,但使用 Kotlin 的构建往往比使用 Groovy 的构建速度慢,因此在决定是否迁移时请考虑构建性能。
此页面提供了有关将 Android 应用的 Gradle 构建文件从 Groovy 转换为 Kotlin 的基本信息。有关更全面的迁移指南,请参阅 Gradle 的 官方文档。
时间线
从 Android Studio Giraffe 开始,新项目默认使用 Kotlin DSL (build.gradle.kts
) 进行构建配置。这比使用 Groovy DSL (build.gradle
) 提供了更好的编辑体验,具有语法高亮显示、代码补全和导航到声明的功能。要了解更多信息,请参阅 Gradle Kotlin DSL 入门指南。
常用术语
Kotlin DSL: 主要指 Android Gradle 插件 Kotlin DSL,或者偶尔指 底层的 Gradle Kotlin DSL。
在本迁移指南中,“Kotlin”和“Kotlin DSL”可以互换使用。同样,“Groovy”和“Groovy DSL”也可以互换使用。
脚本文件命名
脚本文件扩展名基于构建文件所使用的语言。
- 用 Groovy 编写的 Gradle 构建文件使用
.gradle
文件名扩展名。 - 用 Kotlin 编写的 Gradle 构建文件使用
.gradle.kts
文件名扩展名。
转换语法
Groovy 和 Kotlin 之间的语法存在一些差异,因此您需要在构建脚本中应用这些更改。
向方法调用添加括号
Groovy 允许您省略方法调用中的括号,而 Kotlin 则需要括号。要迁移您的配置,请向这些方法调用添加括号。此代码显示如何在 Groovy 中配置设置
compileSdkVersion 30
这是用 Kotlin 编写的相同代码
compileSdkVersion(30)
向赋值调用添加 =
Groovy DSL 允许您在分配属性时省略赋值运算符 =
,而 Kotlin 则需要它。此代码显示如何在 Groovy 中分配属性
java {
sourceCompatibility JavaVersion.VERSION_17
targetCompatibility JavaVersion.VERSION_17
}
此代码显示如何在 Kotlin 中分配属性
java {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
转换字符串
以下是 Groovy 和 Kotlin 之间的字符串差异
- 字符串的双引号:虽然 Groovy 允许使用单引号定义字符串,但 Kotlin 则需要双引号。
-
点表达式中的字符串插值:在 Groovy 中,对于点表达式的字符串插值,你只需要使用
$
前缀即可,但 Kotlin 要求你将点表达式用花括号括起来。例如,在 Groovy 中,你可以使用$project.rootDir
,如下所示myRootDirectory = "$project.rootDir/tools/proguard-rules-debug.pro"
然而,在 Kotlin 中,上述代码会对
project
调用toString()
方法,而不是对project.rootDir
调用。要获取根目录的值,请将${project.rootDir}
表达式用花括号括起来。myRootDirectory = "${project.rootDir}/tools/proguard-rules-debug.pro"
要了解更多信息,请参阅 Kotlin 文档中的字符串模板。
重命名文件扩展名
在迁移构建文件内容时,为每个构建文件追加 .kts
。例如,选择一个构建文件,例如 settings.gradle
文件。将文件重命名为 settings.gradle.kts
,并将文件内容转换为 Kotlin。确保在迁移每个构建文件后,你的项目仍然可以编译。
先迁移你最小的文件,积累经验,然后再继续迁移。你可以在一个项目中混合使用 Kotlin 和 Groovy 构建文件,所以请花时间仔细进行迁移。
将 def
替换为 val
或 var
将 def
替换为 val
或 var
,这是在 Kotlin 中定义变量的方式。这是 Groovy 中的变量声明。
def building64Bit = false
这是用 Kotlin 编写的相同代码
val building64Bit = false
在布尔属性前添加前缀 is
Groovy 使用基于属性名称的属性推断逻辑。对于布尔属性 foo
,其 *推断方法* 可以是 getFoo
、setFoo
或 isFoo
。因此,一旦转换为 Kotlin,你需要将属性名称更改为 Kotlin 不支持的推断方法。例如,对于 buildTypes
DSL 布尔元素,你需要在它们前面添加前缀 is
。这段代码展示了如何在 Groovy 中设置布尔属性。
android {
buildTypes {
release {
minifyEnabled true
shrinkResources true
...
}
debug {
debuggable true
...
}
...
以下是 Kotlin 中的相同代码。请注意,属性前缀为 is
。
android {
buildTypes {
getByName("release") {
isMinifyEnabled = true
isShrinkResources = true
...
}
getByName("debug") {
isDebuggable = true
...
}
...
转换列表和映射
Groovy 和 Kotlin 中的列表和映射使用不同的语法定义。Groovy 使用 []
,而 Kotlin 使用 listOf
或 mapOf
显式调用集合创建方法。迁移时,请确保将 []
替换为 listOf
或 mapOf
。
以下是 Groovy 和 Kotlin 中定义列表的方法
jvmOptions += ["-Xms4000m", "-Xmx4000m", "-XX:+HeapDumpOnOutOfMemoryError</code>"]
这是用 Kotlin 编写的相同代码
jvmOptions += listOf("-Xms4000m", "-Xmx4000m", "-XX:+HeapDumpOnOutOfMemoryError")
以下是 Groovy 和 Kotlin 中定义映射的方法
def myMap = [key1: 'value1', key2: 'value2']
这是用 Kotlin 编写的相同代码
val myMap = mapOf("key1" to "value1", "key2" to "value2")
配置构建类型
在 Kotlin DSL 中,只有 debug 和 release 构建类型是隐式可用的。所有其他自定义构建类型必须手动创建。
在 Groovy 中,你可以使用 debug、release 和某些其他构建类型,而无需事先创建它们。以下代码片段展示了在 Groovy 中使用 debug
、release
和 benchmark
构建类型的配置。
buildTypes {
debug {
...
}
release {
...
}
benchmark {
...
}
}
要在 Kotlin 中创建等效的配置,你必须显式创建 benchmark
构建类型。
buildTypes {
debug {
...
}
release {
...
}
register("benchmark") {
...
}
}
从 buildscript 块迁移到 plugins 块
如果你的构建使用buildscript {}
块向项目添加插件,则应重构为改用plugins {}
块。plugins {}
块使应用插件更容易,并且与版本目录配合良好。
此外,当你在构建文件中使用 plugins {}
块时,即使构建失败,Android Studio 也知道上下文。此上下文有助于修复 Kotlin DSL 文件,因为它允许 Studio IDE 执行代码补全并提供其他有用的建议。
查找插件 ID
buildscript {}
块使用插件的Maven 坐标(例如 com.android.tools.build:gradle:7.4.0
)将插件添加到构建类路径,而 plugins {}
块则使用插件 ID。
对于大多数插件,插件 ID 是使用 apply plugin
应用插件时使用的字符串。例如,以下插件 ID 是 Android Gradle Plugin 的一部分:
com.android.application
com.android.library
com.android.lint
com.android.test
你可以在Google Maven 存储库中找到完整的插件列表。
Kotlin 插件可以通过多个插件 ID 来引用。我们建议使用命名空间插件 ID,并根据下表将简写形式重构为命名空间插件 ID。
简写插件 ID | 命名空间插件 ID |
---|---|
kotlin |
org.jetbrains.kotlin.jvm |
kotlin-android |
org.jetbrains.kotlin.android |
kotlin-kapt |
org.jetbrains.kotlin.kapt |
kotlin-parcelize |
org.jetbrains.kotlin.plugin.parcelize |
你也可以在Gradle Plugin Portal、Maven Central Repository 和Google Maven 存储库上搜索插件。阅读开发自定义 Gradle 插件以了解有关插件 ID 如何工作的更多信息。
执行重构
一旦你知道了你使用的插件的 ID,请执行以下步骤:
如果你的
buildscript {}
块中仍然声明了插件的存储库,请将其移动到settings.gradle
文件。将插件添加到顶级
build.gradle
文件中的plugins {}
块中。你需要在此处指定插件的 ID 和版本。如果插件不需要应用于根项目,请使用apply false
。从顶级
build.gradle.kts
文件中删除classpath
条目。通过将插件添加到模块级
build.gradle
文件中的plugins {}
块中来应用插件。你只需要在此处指定插件的 ID,因为版本是从根项目继承的。从模块级
build.gradle
文件中删除插件的apply plugin
调用。
例如,此设置使用 buildscript {}
块。
// Top-level build.gradle file
buildscript {
repositories {
google()
mavenCentral()
gradlePluginPortal()
}
dependencies {
classpath("com.android.tools.build:gradle:7.4.0")
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.8.0")
...
}
}
// Module-level build.gradle file
apply(plugin: "com.android.application")
apply(plugin: "kotlin-android")
这是使用 plugins {}
块的等效设置。
// Top-level build.gradle file
plugins {
id 'com.android.application' version '7.4.0' apply false
id 'org.jetbrains.kotlin.android' version '1.8.0' apply false
...
}
// Module-level build.gradle file
plugins {
id 'com.android.application'
id 'org.jetbrains.kotlin.android'
...
}
// settings.gradle
pluginManagement {
repositories {
google()
mavenCentral()
gradlePluginPortal()
}
}
转换 plugins 块
从 plugins {}
块应用插件在 Groovy 和 Kotlin 中类似。以下代码展示了在使用版本目录时如何在 Groovy 中应用插件。
// Top-level build.gradle file
plugins {
alias libs.plugins.android.application apply false
...
}
// Module-level build.gradle file
plugins {
alias libs.plugins.android.application
...
}
以下代码展示了如何在 Kotlin 中执行相同的操作。
// Top-level build.gradle.kts file
plugins {
alias(libs.plugins.android.application) apply false
...
}
// Module-level build.gradle.kts file
plugins {
alias(libs.plugins.android.application)
...
}
以下代码展示了在*不*使用版本目录时如何在 Groovy 中应用插件。
// Top-level build.gradle file
plugins {
id 'com.android.application' version '7.3.0' apply false
...
}
// Module-level build.gradle file
plugins {
id 'com.android.application'
...
}
以下代码展示了如何在 Kotlin 中执行相同的操作。
// Top-level build.gradle.kts file
plugins {
id("com.android.application") version "7.3.0" apply false
...
}
// Module-level build.gradle.kts file
plugins {
id("com.android.application")
...
}
有关 plugins {}
块的更多详细信息,请参阅 Gradle 文档中的应用插件。
其他
有关其他功能的 Kotlin 代码示例,请参阅以下文档页面:
- 如果你有 ProGuard 配置,请参考启用缩减、混淆和优化。
- 如果你有
signingConfig {}
块,请参考从构建文件中删除签名信息。 - 如果你使用项目范围属性,请参考配置项目范围属性。
已知问题
目前,一个已知问题是,与 Groovy 相比,Kotlin 的构建速度可能会更慢。
如何报告问题
有关如何提供我们需要的信息来分类你的问题的信息,请参阅构建工具和 Gradle 错误的详细信息。然后,使用 Google 的公共问题跟踪器提交错误。
更多资源
有关用 Kotlin 编写的 Gradle 构建文件的实际示例,请参阅 GitHub 上的Now In Android 示例应用。