Android Gradle 插件 4.0 支持在 Gradle 构建装备中运用 Kotlin 脚本 (KTS),用于代替 Groovy(过去在 Gradle 装备文件中运用的编程言语)。

将来,KTS 会比 Groovy 更适合用于编写 Gradle 脚本,因为选用 Kotlin 编写的代码可读性更高,并且 Kotlin 供给了更好的编译时查看和 IDE 支持

尽管与 Groovy 比较,KTS 当时能更好地在 Android Studio 的代码编辑器中集成,但选用 KTS 的构建速度往往比选用 Groovy 慢,因而在搬迁到 KTS 时应考虑构建性能

常用术语

KTS:指Kotlin脚本,是Gradle在构建装备文件中运用的一种 Kotlin 言语方式。Kotlin 脚本是可从命令行运行的 Kotlin 代码。

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

文件命名

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

搬迁思路

Groovy 的语法和 Kotlin 的语法尽管相差不小,但在 Gradle DSL 的规划上,还是尽可能保持了统一性,这显然也是为了降低咱们的学习和搬迁本钱。正因为如此,尽管咱们还是要对两门言语的一些语法细节进行批量处理,搬迁进程实际上并不复杂。

处理字符串字面量

主要修正点在于 settings.gradle以及几个 build.gradle

Groovy 中,单引号引起来的也是字符串字面量,因而咱们会面临很多这样的写法:

include ':app', ':tdc_core', ':tdc_uicompat', ':tdc_utils'

这在 Kotlin 中是不允许的,因而需求想办法将字符串字面量单引号统一改为双引号,可以运用Android Studio的 大局正则替换

Gradle迁移指南:从Groovy到KTS

  • 匹配框输入正则表达式'(.*?[^\])',替换框中填写"$1",这里的$1对应于正则表达式傍边的第一个元组,如果有多个元组,可以用$n来表明,其中$0表明匹配到的整个字符
  • 过滤文件后缀,咱们只对*.gradle文件做替换
  • 在文件后缀后边的漏斗傍边挑选 Excepts String literals and Comments,表明咱们只匹配代码部分
  • 在输入框后边挑选.*,蓝色高亮表明启用正则匹配

查看匹配内容,对匹配过错的部分进行修正,点击 Replace All,一切单引号会变成双引号:

include ":app", ":tdc_core", ":tdc_uicompat", ":tdc_utils"

给办法调用加上括号

仍以 settings.gradle为例:

include ":app", ":tdc_core", ":tdc_uicompat", ":tdc_utils"

此处实际是一个办法调用,在 Groovy 中只要没有歧义,就可以把办法调用的括号省掉,这在 Kotlin 中是不行的,因而需求统一做加括号处理,选用 大局正则替换 办法:

Gradle迁移指南:从Groovy到KTS

  • 匹配框输入正则表达式(\w+) (([^={\s]+)(.*)),替换框中填写$1($2),其他装备与前面替换引号一样

查看匹配内容,对匹配过错的部分进行修正,点击 Replace All,一切办法调用都加上了括号:

include(":app", ":tdc_core", ":tdc_uicompat", ":tdc_utils")

开端搬迁

搬迁 settings.gradle

首先,将文件名改为 settings.gradle.kts, 然后 sync。 经过前面两步操作,settings.gradle内容已经是合法的 Kotlin 代码了。

搬迁根目录下的 build.gradle

给文件增加 .kts后缀,sync之后开端处理报错:

拜访extra扩展

过去咱们都是经过 ext拜访 project目标动态属性(参阅视频:Project属性都是哪里来的?),Groovy的动态特性支持了这一语法,但Kotlin作为一门静态言语是不支持的。因而想要拜访ext,就需求运用extra扩展,或者 getProperties()["ext"],所以:

ext.kotlin_version = "1.4.30"

等价于

extra["kotlin_version"] = "1.4.30"

接下来便是对 kotlin_version的拜访了,需求将它取出来再运用:

val kotlin_version: String by extra
...
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version")

创建任务

参阅 clean任务的修正办法:

// 办法一(推荐运用)
tasks.register<Delete>("clean") {
    delete(rootProject.buildDir)
}
// 办法二
task("clean", Delete::class) {
    delete(rootProject.buildDir)
}

在 Groovy 傍边 Delete 类型是作为参数经过 Key-Value 的方式传递的,Kotlin 傍边直接把它作为泛型参数传入,这样规划是十分契合 Kotlin 的规划思想。

maven装备

maven语法比较简单,直接修正为:

repositories {
    google()
    mavenCentral()
    maven("https://jitpack.io/")
    maven("http://maven.xxx.com/") {
        // 信赖http协议
        isAllowInsecureProtocol = true
    }
}

搬迁app模块下的 build.gradle

保证顶部 plugins装备正确,等候IDE创建索引完毕,各个元素就可以拜访了:

Gradle迁移指南:从Groovy到KTS

语法细节差异,依据代码提示修正即可,完好装备参阅末尾示例。

显现和隐式 buildTypes

在 Kotlin DSL 中,某些buildTypes(如debugrelease,)是隐式供给的。可是,其他buildTypes则有必要手动创建。

在 Groovy 中,你可能有 debug, release, staging

buildTypes {
    debug {
    }
    release {
    }
    staging {
    }
}

在 KTS 中,仅 debugrelease是隐式供给的,staging有必要手动创建:

buildTypes {
    getByName("debug") {
    }
    getByName("release") {
    }
    create("staging") {
    }
}

参阅示例

settings.gradle.kts

include(":app", ":tdc_core", ":tdc_uicompat", ":tdc_utils")

build.gradle.kts

// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
    repositories {
        google()
        mavenCentral()
    }
    dependencies {
        classpath("com.android.tools.build:gradle:7.0.4")
        classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.7.10")
        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}
allprojects {
    repositories {
        google()
        mavenCentral()
        maven("https://jitpack.io/")
        maven("http://maven.xxx.com/") {
            // 信赖http协议
            isAllowInsecureProtocol = true
        }
    }
    configurations.all {
        resolutionStrategy.apply {
            cacheChangingModulesFor(0, "seconds")
            cacheDynamicVersionsFor(0, "seconds")
        }
    }
}
tasks.register<Delete>("clean") {
    delete(rootProject.buildDir)
}

app/build.gradle.kts

plugins {
    id("com.android.application")
    kotlin("android")
}
android {
    compileSdk = 31
    defaultConfig {
        applicationId = "com.xx.component"
        minSdk = 21
        targetSdk = 31
        versionCode = 1
        versionName = "1.0"
        multiDexEnabled = true
        testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
    }
    signingConfigs {
        create("keyStore") {
            keyAlias = "component"
            keyPassword = "123456"
            storeFile = file("xx.keystore")
            storePassword = "123456"
        }
    }
    buildTypes {
        val signConfig = signingConfigs.getByName("keyStore")
        getByName("debug") {
            isMinifyEnabled = false
            proguardFiles(
                getDefaultProguardFile("proguard-android-optimize.txt"),
                "proguard-rules.pro"
            )
            signingConfig = signConfig
        }
        getByName("release") {
            isMinifyEnabled = false
            proguardFiles(
                getDefaultProguardFile("proguard-android-optimize.txt"),
                "proguard-rules.pro"
            )
            signingConfig = signConfig
        }
        create("staging") {
            isMinifyEnabled = false
            proguardFiles(
                getDefaultProguardFile("proguard-android-optimize.txt"),
                "proguard-rules.pro"
            )
            signingConfig = signConfig
        }
    }
    compileOptions {
        sourceCompatibility = JavaVersion.VERSION_1_8
        targetCompatibility = JavaVersion.VERSION_1_8
    }
    kotlinOptions {
        jvmTarget = "1.8"
    }
    viewBinding.isEnabled = true
}
dependencies {
    implementation("androidx.core:core-ktx:1.7.0")
    implementation("androidx.appcompat:appcompat:1.4.1")
    testImplementation("junit:junit:4.+")
    androidTestImplementation("androidx.test.ext:junit:1.1.3")
    androidTestImplementation("androidx.test.espresso:espresso-core:3.4.0")
}
Gradle迁移指南:从Groovy到KTS