将 build 配置从 Groovy 迁移到 Kotlin

Android Gradle 插件 4.0 支持在 Gradle build 配置中使用 Kotlin,以替代 Groovy(Gradle 配置文件中通常使用的编程语言)。

在编写 Gradle 脚本方面,Kotlin 比 Groovy 更优,因为 Kotlin 更易于阅读,并且提供了更好的编译时检查和 IDE 支持。

虽然与 Groovy 相比,Kotlin 目前在 Android Studio 的代码编辑器中提供了更好的集成,但使用 Kotlin 的 build 往往比使用 Groovy 的 build 慢,因此在决定是否迁移时,请考虑 build 性能。

本页介绍了有关将 Android 应用的 Gradle build 文件从 Groovy 转换为 Kotlin 的基本信息。如需查看更全面的迁移指南,请参阅 Gradle 的官方文档

时间轴

从 Android Studio Giraffe 开始,新项目将默认使用 Kotlin DSL (build.gradle.kts) 进行 build 配置。与 Groovy DSL (build.gradle) 相比,这种方法具有语法突出显示、代码补全和声明导航等功能,可提供更好的修改体验。如需了解详情,请参阅 Gradle Kotlin DSL Primer

常用术语

Kotlin DSL:主要是指 Android Gradle 插件 Kotlin DSL,有时也指底层 Gradle Kotlin DSL

在本迁移指南中,“Kotlin”和“Kotlin DSL”可以互换使用。同样,“Groovy”和“Groovy DSL”可互换使用。

脚本文件命名

脚本文件扩展名取决于编写 build 文件所用的语言:

  • 用 Groovy 编写的 Gradle build 文件使用 .gradle 文件扩展名。
  • 用 Kotlin 编写的 Gradle build 文件使用 .gradle.kts 文件扩展名。

转换语法

Groovy 和 Kotlin 的语法之间存在一些普遍差异,因此您需要在 build 脚本中应用以下更改。

为方法调用添加圆括号

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(而非 project.rootDir)调用 toString()。如需获取根目录的值,请使用大括号括住 ${project.rootDir} 表达式:

        myRootDirectory = "${project.rootDir}/tools/proguard-rules-debug.pro"
        

    如需了解详情,请参阅 Kotlin 文档中的字符串模板

重命名文件扩展名

请在迁移每个 build 文件的内容时将 .kts 添加到其文件扩展名后。例如,选择一个 build 文件(如 settings.gradle 文件)。将该文件重命名为 settings.gradle.kts,然后将其内容转换为 Kotlin 代码。请确保您的项目在迁移每个 build 文件之后仍然可以编译。

请先迁移最小的文件以便积累经验,然后再继续。项目中可以混合使用 Kotlin 和 Groovy build 文件,因此请花些时间仔细进行迁移。

def 替换为 valvar

def 替换为 valvar,这是在 Kotlin 中定义变量的方式。以下是 Groovy 中的变量声明:

def building64Bit = false

以下是使用 Kotlin 编写的相同代码:

val building64Bit = false

为布尔值属性添加 is 前缀

Groovy 会根据属性名称使用属性推导逻辑。对于布尔值属性 foo,其推导的方法可以是 getFoosetFooisFoo因此,在转换为 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 使用 listOfmapOf 显式调用集合创建方法。迁移时,请务必将 [] 替换为 listOfmapOf

以下是 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")

配置 build 类型

在 Kotlin DSL 中,只有调试和发布 build 类型是隐式提供的。所有其他自定义 build 类型都必须手动创建。

在 Groovy 中,您无需先创建就可以使用调试、发布和某些其他 build 类型。以下代码段展示了 Groovy 中具有 debugreleasebenchmark build 类型的配置。

buildTypes {
 debug {
   ...
 }
 release {
   ...
 }
 benchmark {
   ...
 }
}

如需在 Kotlin 中创建等效配置,您必须显式创建 benchmark build 类型。

buildTypes {
 debug {
   ...
 }

 release {
   ...
 }
 register("benchmark") {
    ...
 }
}

从 buildscript 迁移到插件块

如果您的 build 使用 buildscript {} 代码块向项目添加插件,您应重构为改用 plugins {} 代码块。plugins {} 代码块可让您更轻松地应用插件,并且与版本目录非常兼容。

此外,如果您在 build 文件中使用 plugins {} 代码块,即使构建失败,Android Studio 也会知道上下文。此上下文有助于修复 Kotlin DSL 文件,因为它允许 Studio IDE 执行代码补全并提供其他实用建议。

查找插件 ID

虽然 buildscript {} 代码块使用插件的 Maven 坐标(例如 com.android.tools.build:gradle:7.4.0)将插件添加到 build 类路径,但 plugins {} 代码块会改用插件 ID。

对于大多数插件,插件 ID 是使用 apply plugin 应用它们时使用的字符串。例如,以下插件 ID 是 Android Gradle 插件的一部分:

  • 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 插件门户Maven Central RepositoryGoogle Maven 制品库中搜索插件。 如需详细了解插件 ID 的工作原理,请参阅开发自定义 Gradle 插件

执行重构

知道所用插件的 ID 后,请执行以下步骤:

  1. 如果您仍有用于存放在 buildscript {} 代码块中声明的插件的代码库,请改为将其移至 settings.gradle 文件。

  2. 将插件添加到顶级 build.gradle 文件的 plugins {} 代码块中。您需要在此处指定插件的 ID 和版本。如果不需要将该插件应用到根项目,请使用 apply false

  3. 从顶级 build.gradle.kts 文件中移除 classpath 条目。

  4. 将插件添加到模块级 build.gradle 文件的 plugins {} 代码块中,即可应用插件。您只需在此处指定插件的 ID,因为相应版本继承自根项目。

  5. 从模块级 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 块

在 Groovy 和 Kotlin 中,从 plugins {} 块应用插件类似。以下代码展示了当您使用版本目录时如何在 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 实现其他功能的代码示例,请参阅以下文档页面:

已知问题

目前,一个已知问题是采用 Kotlin 的构建速度可能比使用 Groovy 慢。

如何报告问题

如需了解如何提供对问题进行分类所需的信息,请参阅构建工具和 Gradle bug 详细信息。然后,使用 Google 公开问题跟踪器来提交 bug。

更多资源

如需查看使用 Kotlin 编写的 Gradle build 文件的可运行示例,请参阅 GitHub 上的 Now In Android 示例应用