最近写了一些 Gradle 脚本,Groovy 十分糟糕的体验让我想尝试把 Groovy 迁移到 Kotlin 上
为什么不想用 Groovy
- 几乎没有智能提示
- 无法直接查看 groovy api 的源码
- 上面两条导致,一个 Android 开发者无法快速上手 Gradle 来编写一些复杂的脚本
Kotlin 编写 Gradle 的优势
- 静态语言的所有优势
- Kotlin DSL 的特性可以像 Groovy 一样简洁
- 完整的 IDE 支持
- buildSrc 新特性可以像管理 Java 文件一样管理所有脚本
版本要求
- JDK 1.8 及以上
- Gradle 5.0 及以上
- 最新版 Android Gradle 插件
开始迁移
首先,把你的 build.gradle 文件名改为 build.gradle.kts,( 后缀竟然不是 kt )
语法变化
尽管 Kotlin DSL 和 Groovy DSL 很像,但是还是没有脱离 Kotlin 的语法规则
-
所有的 ' ' 变成 " ",因为 Kotlin 的字符串必须使用双引号
-
空格变成方法调用或者赋值,比如:
include ':app', ':basemodule', ':home', ':read', ':data', ':personalcenter'
改为
include(":app", ":basemodule", ":home", ":read", ":data", ":personalcenter")
defaultConfig { versionCode Build.versionCode }
改为
defaultConfig { versionCode = Build.versionCode }
-
map的使用,例如:
implementation fileTree(dir: 'libs', include: ['*.jar'])
改为
implementation(fileTree(mapOf("include" to listOf("*.jar"), "dir" to "libs")))
其它API的变化
-
plugins
apply plugin: 'com.android.application' apply plugin: 'kotlin-android' apply plugin: 'kotlin-android-extensions' apply plugin: 'kotlin-kapt'
现在变成:
plugins { id("com.android.application") kotlin("android") kotlin("kapt") kotlin("android.extensions") }
这里的 kotlin这个方法很有意思,可以点进去看一下源码:
fun PluginDependenciesSpec.kotlin(module: String): PluginDependencySpec = id("org.jetbrains.kotlin.$module")
发现就是第一行 id 那个方法的扩展😆
-
task
原来的写法:
task clean(type: Delete) { delete rootProject.buildDir }
这里写法比较自由,可以使用 ProjectExtensions 里的 task 方法:
task("clean", Delete::class) { delete(rootProject.buildDir) }
也可以用 ProjectsDelegate 的 TaskContainer 的 register 方法:
tasks.register("clean", Delete::class) { delete(rootProject.buildDir) }
-
buildType 原来的 release、debug 需要通过 getByName(String name, Action<? super T> configureAction) 这个方法来构建:
buildTypes { getByName("release") { isMinifyEnabled = true isZipAlignEnabled = true isShrinkResources = true proguardFiles(getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro") } }
新特性 buildSrc
Gradle 5.0 之后推出了一个叫 buildSrc 的东西,简单来说就是把你的脚本相关代码放在一个文件夹里单独管理,build.gradle 最终可以直接调用到这些代码,这也是这次迁移最吸引我的一个特性。
目录结构:

你会发现 buildSrc 就是一个普通的 module,有自己的 build.gradle,有 build 产物,文件结构也遵循src/main/kotlin(或者java)。
构建步骤
-
根目录下新建一个 buildSrc 文件夹
-
新建 src/main/kotlin目录
-
新建一个 build.gradle.kts 文件,内容如下:
plugins { `kotlin-dsl` } repositories { // The org.jetbrains.kotlin.jvm plugin requires a repository // where to download the Kotlin compiler dependencies from. jcenter() }
同步一下即可开始编写你的代码
可以做哪些事
最基础的就是管理所有的依赖和版本号,比如
object Versions {
const val support = "27.1.1"
const val constraint = "1.1.3"
const val lifecycle = "1.1.1"
// ...
}
// ...
object Deps {
object Support {
val appCompat = "com.android.support:appcompat-v7:${Versions.support}"
val constraint = "com.android.support.constraint:constraint-layout:${Versions.constraint}"
val design = "com.android.support:design:${Versions.support}"
}
object Lifecycle {
val extensions = "android.arch.lifecycle:extensions:${Versions.lifecycle}"
}
object Retrofit {
val runtime = "com.squareup.retrofit2:retrofit:${Versions.retrofit}"
val gson = "com.squareup.retrofit2:converter-gson:${Versions.retrofit}"
val rxjava2 = "com.squareup.retrofit2:adapter-rxjava2:${Versions.retrofit}"
}
// ...
}
另外,还可以把共有的依赖封装进方法,分类管理你的各种 task 等等。
迁移过程中遇到的一些问题
- 很多 API 找不到,当你开始迁移一个 build.gradle 文件时,会发现一片红色,很多 api 不识别,不要慌,因为有些api是编译时生成的,并不包含在标准库里,当你把所有语法都改完之后重新编译就会正常
- Groovy 和 Kotlin 互通性,一些 groovy 脚本通过 apply from 在 kts 里仍然可以生效,但是想调用里面的东西……基本不可能,所有要迁移的话,最好一次全部迁移掉