赞
踩
目录
Android Gradle 插件 4.0 支持在 Gradle 构建配置中使用 Kotlin 脚本 (KTS),用于替代 Groovy(过去在 Gradle 配置文件中使用的编程语言)。
将来,KTS 会比 Groovy 更适合用于编写 Gradle 脚本,因为采用 Kotlin 编写的代码可读性更高,并且 Kotlin 提供了更好的编译时检查和 IDE 支持。
虽然与 Groovy 相比,KTS 当前能更好地在 Android Studio 的代码编辑器中集成,但采用 KTS 的构建速度往往比采用 Groovy 慢,因此在迁移到 KTS 时应考虑构建性能。
本页介绍了有关将 Android 应用的 Gradle build 文件从 Groovy 转换为 KTS 的基本信息。
如需查看更全面的迁移指南,请参阅 Gradle 的官方文档。
⚠️ 采用 KTS 的构建速度往往比采用 Groovy 慢,因此在迁移到 KTS 时应考虑构建性能。
KTS:是指 Kotlin 脚本,这是 Gradle 在构建配置文件中使用的一种 Kotlin 语言形式。Kotlin 脚本是可从命令行运行的 Kotlin 代码。
Kotlin DSL:主要是指 Android Gradle 插件 Kotlin DSL,有时也指底层 Gradle Kotlin DSL。
在讨论从 Groovy 迁移时,术语“KTS”和“Kotlin DSL”可以互换使用。换句话说,“将 Android 项目从 Groovy 转换为 KTS”与“将 Android 项目从 Groovy 转换为 Kotlin DSL”实际上是一个意思。
- 用 Groovy 编写的 Gradle build 文件使用
.gradle
文件扩展名。- 用 Kotlin 编写的 Gradle build 文件使用
.gradle.kts
文件扩展名。
⚠️ 在迁移之前,我们要一次迁移一个文件:
由于可以在项目中结合使用 Groovy build 文件和 KTS build 文件,因此将项目转换为 KTS 的一个简单方法是先选择一个简单的 build 文件(例如 settings.gradle
),将其重命名为 settings.gradle.kts
,然后将其内容转换为 KTS。之后,确保您的项目在迁移每个 build 文件之后仍然可以编译。
一些简单的 Kotlin 和 Groovy 语言差异会使转换脚本变得乏味:
字符串:Groovy 可以用单引号'string'或双引号引用"string",而 KTS 需要双引号"string"。
括号:Groovy 允许在调用函数时省略括号,而 KTS 需要括号。
赋值运算符:Groovy 允许在分配属性时省略赋值运算符(=),而 Kotlin 需要赋值运算符(=)。
作为迁移的第一步,建议通过以下方式准备您的 Groovy 构建脚本
使用双引号统一引号,
分别使用括号和赋值运算符。
示例1.使用双引号统一引号
- android {
- compileSdkVersion 30
- buildToolsVersion '30.0.2'
- ...
- }
-
- dependencies {
- implementation 'com.acme:example:1.0'
- }
变成 KTS - app/gradle:
- android {
- compileSdkVersion 30
- buildToolsVersion = "30.0.2"
- ...
- }
-
- dependencies {
- implementation "com.acme:example:1.0"
- }
继续示例1中的更改
示例2.分别使用括号和赋值运算符
- android {
- compileSdkVersion(30)
- buildToolsVersion = "30.0.2"
- ...
- }
-
- dependencies {
- implementation("com.acme:example:1.0")
- }
⚠️ 后者涉及更多,因为在 Groovy 脚本中区分函数调用和属性分配可能并非易事,我们一开始并不能明确哪些地方该使用括号还是赋值运算符。一个好的策略是首先对所有不明确的语句进行属性分配,然后通过将失败的语句转换为函数调用来修复构建。
接下来,我们一起来看看具体的替换:
plugins
代码块迁移Groovy 中的以下代码:
- apply plugin: 'com.android.application'
- apply plugin: 'kotlin-android'
- apply plugin: 'dagger.hilt.android.plugin'
- // or
- plugins {
- id 'com.android.application'
- id 'kotlin-android'
- id 'dagger.hilt.android.plugin'
- }
-
- apply from: '../signing.gradle'
在 KTS 中变为以下代码:
- plugins {
- id("com.android.application")
- id("kotlin-android")
- id("dagger.hilt.android.plugin")
- }
-
-
- apply(from = "../signing.gradle")
这里 id("kotlin-android") 也能写成 kotlin("android")
⚠️ plugins
代码块仅解析 Gradle 插件门户中提供的插件或使用 pluginManagement
代码块指定的自定义存储库中提供的插件。如果插件来自插件门户中不存在的 buildScript
依赖项,那么这些插件在 Kotlin 中就必须使用 apply
才能应用。例如:
apply(plugin = "kotlin-android")
buildTypes
⚠️ 在 Kotlin DSL 中,某些 buildTypes
(如 debug
和 release,
)是隐式提供的。但是,其他 buildTypes
则必须手动创建。
Groovy - buildTypes
:
- // 例如,在 Groovy 中,您可能有 debug、release 和 staging
-
- buildTypes
- debug {
- ...
- }
- release {
- ...
- }
- staging {
- ...
- }
在 KTS 中,仅 debug
和 release,
buildTypes
是隐式提供的,而 staging
则必须由您手动create(创建)出来:
KTS - buildTypes:
- buildTypes
- getByName("debug") {
- ...
- }
- getByName("release") {
- ...
- }
- create("staging") {
- ...
- }
补充:buildTypes-debug
的改变
Groovy - buildTypes-debug:
- buildTypes {
- debug {
- minifyEnabled false
- testCoverageEnabled project.hasProperty("coverage")
- debuggable true
- applicationIdSuffix ".dev"
- versionNameSuffix "-DEV"
- signingConfig signingConfigs.debug
- proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
- }
- release {
- }
- }
KTS - buildTypes-debug 对应的更改:
- buildTypes {
- getByName("debug") {
- isMinifyEnabled = false
- isTestCoverageEnabled = project.hasProperty("coverage")
- isDebuggable = true
- applicationIdSuffix = ".dev"
- versionNameSuffix = "-DEV"
- signingConfig = signingConfigs.getByName("debug")
- proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
- }
-
- getByName("release") {
- ...
- }
- }
Groovy - defaultConfig:
- defaultConfig {
- applicationId "com.android.testplaydemo"
- minSdkVersion 21
- targetSdkVersion 30
- versionCode 1
- versionName "1.0"
-
- testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
- }
KTS - defaultConfig:
- defaultConfig {
- applicationId = "com.android.testplaydemo"
- minSdkVersion(21)
- targetSdkVersion(30)
- versionCode = 1
- versionName = "1.0"
-
- testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
- }
Groovy -
signingConfigs:
- signingConfigs {
- release {
- keyAlias 'test'
- keyPassword '123456'
- storeFile file('../test.jks')
- storePassword '123456'
- v1SigningEnabled true
- v2SigningEnabled true
- }
- debug {
- keyAlias 'test'
- keyPassword '123456'
- storeFile file('../test.jks')
- storePassword '123456'
- }
- }
KTS -
signingConfigs:
- signingConfigs {
- create("release") {
- keyAlias = "test"
- keyPassword = "123456"
- storeFile = File("../test.jks")
- storePassword = "123456"
- isV1SigningEnabled = true
- isV2SigningEnabled = true
- }
- getByName("debug") {
- keyAlias = "test"
- keyPassword = "123456"
- storeFile = File("../test.jks")
- storePassword = "123456"
- }
- }
Groovy 示例:
- // 自定义多渠道打包 apk名称
- applicationVariants.all { variant ->
- def buildType = variant.buildType.name
- variant.outputs.all { output ->// each 改为 all
- def date = new Date().format("ddHHmm", TimeZone.getTimeZone("GMT+08"))
- def fileName = "MVVM_${productFlavors[0].name}_${versionName}_${versionCode}_${date}.apk"
- def outFile = output.outputFile
- if (outFile != null && buildType == "release") {
- outputFileName = fileName // output.outputFile 改为 outputFileName
- }
- }
- }
-
- // 多渠道配置
- flavorDimensions "code"
- productFlavors {
- google {
- }
- baidu {
- }
- other {
- }
- }
- productFlavors.all {
- flavor -> flavor.manifestPlaceholders = [CHANNEL_VALUE: name]
- }
KTS 示例:
- // 自定义多渠道打包 apk名称
- applicationVariants.all {
- val buildType = buildType.name
- outputs.all {
- if (this is com.android.build.gradle.internal.api.ApkVariantOutputImpl) {
- if (buildType == "release") {
- outputFileName = "DEMO_v${versionCode}_${flavorName}_${Versions.dateFormat}.apk"
- }
- }
- }
- }
-
- // 多渠道配置
- flavorDimensions("code")
- productFlavors {
- create("google")
- create("baidu")
- create("other")
- }
- productFlavors.all {
- manifestPlaceholders["CHANNEL_VALUE"] = name
- }
Groovy -
compileOptions:
- compileOptions {
- sourceCompatibility JavaVersion.VERSION_1_8
- targetCompatibility JavaVersion.VERSION_1_8
- }
- kotlinOptions {
- jvmTarget = '1.8'
- }
KTS -
compileOptions:
- compileOptions {
- sourceCompatibility = JavaVersion.VERSION_1_8
- targetCompatibility = JavaVersion.VERSION_1_8
- }
- kotlinOptions {
- jvmTarget = "1.8"
- }
Groovy -
dependencies:
- dependencies {
- implementation fileTree(dir: "libs", include: ["*.jar"])
- implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
- implementation 'androidx.core:core-ktx:1.6.0'
- implementation 'androidx.appcompat:appcompat:1.3.1'
- implementation 'com.google.android.material:material:1.4.0'
- implementation 'androidx.constraintlayout:constraintlayout:2.1.0'
- testImplementation 'junit:junit:4.12'
- androidTestImplementation 'androidx.test.ext:junit:1.1.3'
- androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
- }
KTS -
dependencies:
- dependencies {
- implementation(fileTree(mapOf("dir" to "libs", "include" to listOf("*.jar"))))
- implementation("org.jetbrains.kotlin:kotlin-stdlib:${Libs.kotlin_version}")
- implementation("androidx.core:core-ktx:1.6.0")
- implementation("androidx.appcompat:appcompat:1.3.1")
- implementation("com.google.android.material:material:1.4.0")
- implementation("androidx.constraintlayout:constraintlayout:2.1.0")
- testImplementation("junit:junit:4.12")
- androidTestImplementation("androidx.test.ext:junit:1.1.3")
- androidTestImplementation("androidx.test.espresso:espresso-core:3.4.0")
- }
⚠️ 需要注意:implementation fileTree(dir: "libs", include: ["*.jar"]) 这行的改动!
在kts中写法为:implementation(fileTree(mapOf("dir" to "libs", "include" to listOf("*.jar")))) 。
关于参数的配置的更改(比如:应用版本号,兼容最低Android sdk版本号,依赖版本号,签名)如下示例:(Groovy)
- // 一般放入 build.gradle 中
- ext {
- minAndroidSdk = 21
- targetSdk = 29
- verCode = automatedVerCode
- verName = "1.0.0-${project.findProperty('buildNumber') ?: 0}"
-
- // 依赖包版本号 配置
- kotlin_version = "1.4.10"
- other_version = "2.2.0"
- }
-
- // 一般会创建一个 signing.gradle 来存放签名配置参数
- ext {
- StoreFile = "test.keystore"
- StorePassword = "202121"
- KeyAlias = "test"
- KeyPassword = "202121"
- }
我们需要删除原来的 ext 参数配置,并在根目录上右键新建 buildSrc 目录。目录结构与文件如下所示:
创建参数的示例:(KTS)
- // 应用版本号/兼容sdk版本号 配置
- object Versions {
- const val applicationId = "com.android.mvvm"
-
- const val minAndroidSdk = 21
- const val targetSdk = 30
- const val verCode = 100 // XYZ
- const val verName = "1.0.0" // X.Y.Z; X = Major, Y = minor, Z = Patch level
- }
-
- // 依赖包版本号 配置
- object Libs {
- const val KOTLIN_VERSION = "1.4.10"
- const val OTHER_VERSION = "2.2.0"
- }
-
- // 签名 配置
- object Signing {
- const val StoreFile = "test.keystore"
- const val StorePassword = "123456"
- const val KeyAlias = "test"
- const val KeyPassword = "123456"
- }
补充:其中需要看下 buildSrc 目录中的 build.gradle.kts 配置:
- // build.gradle.kts
- plugins {
- `kotlin-dsl`
- }
-
- repositories {
- gradlePluginPortal()
- }
以上为 app/build.gradle.kts 的迁移。
需要更多更详细,请查看已迁移文件:app/build.gradle.kts
第一步:需要删除原来的 ext 参数配置;第二步:根据依赖配置做相应的更改:
示例(Groovy)
- // Top-level build file where you can add configuration options common to all sub-projects/modules.
- buildscript {
- ext {
- kotlin_version = "1.4.32"
- other_version = "2.2.0"
- }
-
- repositories {
- google()
- jcenter()
- }
- dependencies {
- classpath "com.android.tools.build:gradle:4.1.2"
- classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
- // NOTE: Do not place your application dependencies here; they belong
- // in the individual module build.gradle files
- }
- }
-
- allprojects {
- repositories {
- google()
- jcenter()
- }
- }
-
- task clean(type: Delete) {
- delete rootProject.buildDir
- }
示例(KTS)
- // Top-level build file where you can add configuration options common to all sub-projects/modules.
- buildscript {
- repositories {
- google()
- jcenter()
- }
- dependencies {
- classpath("com.android.tools.build:gradle:4.0.1")
- classpath(kotlin("gradle-plugin", version = Libs.KOTLIN_VERSION))
- classpath("com.google.dagger:hilt-android-gradle-plugin:${Libs.HILT_VERSION}")
- // NOTE: Do not place your application dependencies here; they belong
- // in the individual module build.gradle.kts files
- }
- }
-
- allprojects {
- repositories {
- google()
- jcenter()
- }
- }
-
- tasks.register("clean", Delete::class) {
- delete(rootProject.buildDir)
- }
⚠️ 这里需要注意创建任务的写法:
- // Groovy
- task clean(type: Delete) {
- delete rootProject.buildDir
- }
-
- // KTS
- tasks.register("clean", Delete::class) {
- delete(rootProject.buildDir)
- }
最后就很简单,示例(Groovy)
- include ':app'
- rootProject.name = "TestDemo"
示例(KTS)
- include(
- ":app"
- )
- rootProject.name = "TestDemo"
如需查看用 KTS 编写的 Gradle build 文件的可运行示例,
请参阅 GitHub上提供的 MVVM 示例应用 - Groovy-To-KTS分支;
也可以参阅 GitHub 上的官方提供的 IOSched 示例应用。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。