Gradle Kotlin DSL

在 Gradle 5.0 之後就可以開始支援在 *.gradle 檔案裡面使用 Kotlin DSL,這篇文章將會講解如何把 Android 專案的 Gradle build script 轉換為使用 Kotlin DSL,讓你可以直接無痛使用 Kotlin 撰寫 *.gradle,而捨棄(超難用)的 Groovy 語法。

更新

很多人私訊問我能不能提供完整的範例程式碼,我準備好開放出來了,可以前往 https://github.com/enginebai/AndroidBase 觀看和 Clone,歡迎給星 ⭐!

為何要做這轉換呢?個人覺得有兩個非常重要的好處:

這邊不會特別解釋 Kotlin DSL 是什麼或語法,有興趣的話可以去 官網 閱讀。

  1. Groovy 是另外一個語言,你還需要另外學習,如果能用一個主要熟悉的語法開發,可以增進開發速度和效率,那是再好不過的事情了。
  2. 轉換到 Kotlin 之後,你就可以善用 IDE 所提供的功能,例如自動完成 (Auto-complete)、重構 (Refactor)、前往定義 (Navigation → Definition) … 等好用的功能。

廢話不多說,讓我們開始進行,這邊有三大部分要實作,我會在 Android Studio 開一個全新的專案來一一講解:

  1. 加入 buildSrc:用 Kotlin 來做依賴管理。
  2. 轉移 *.gradle 檔案:用 Kotlin 來寫。
  3. 完全使用 Kotlin 來管理你的第三方程式庫。

Step1. 加入 buildSrc:用 Kotlin 來做依賴管理

首先在專案的根目錄新增一個資料夾,且命名為 buildSrc

在剛剛建立的 buildSrc 資料夾底下,新增一個檔案 build.gradle.kts,然後新增下列程式碼:

repositories {
   jcenter()
}

plugins {
   `kotlin-dsl`
}

接著,你的 Android Studio 會提示要做 Gradle sync,就按下 Sync Now。且還會提示 “There is a new script context available”,你可以按下 “Apply context” 或者 “Enable auto-reload”。

buildSrc 資料夾底下,新增三層子目錄 src/main/java,然後在這目錄  src/main/java 建立兩個檔案: Versions.kt / Dependencies.kt ,這兩個檔案主要是用來定義 build.gradle 所用到的版本和第三方程式庫,在這兩個 *.kt 檔案你就可以開始使用 Kotlin 語法,寫完之後要記得做 Gradle sync。

接下來,你就可以開始在 build.gradle 檔案裡面使用剛剛在 Versions.kt / Dependencies.kt 所定義好的版本和第三方程式庫變數,這邊我們在 app/build.gradle 使用 Dependencies.kotlinStdLib,你可以發現你可以開始使用 Auto-complete 了!(可能會比較慢才跑出來) 

如果你有看到 Android Studio 有出現自動完成,表示你已經算成功整合 buildSrc 了,你可以在 build.gradle 檔案裡面使用 Kotlin 變數且可以直接前往定義。

滑鼠移過去會出現程式的定義。

Step 2. 轉移 *.gradle 檔案:用 Kotlin 來寫

我們成功在 *.gradle 檔案使用 Kotlin 之後,接下來我們就要把所有既有的 Goovy 語法轉換為 Kotlin 語法,需要轉換的檔案有:

  • settings.gradle
  • Project-level build.gradle
  • 所有 Module-level build.gradle

這邊因為我們範例是全新的專案,所以我們只需要轉換 settings.gradle, project-level build.gradle 和 app/build.gradle 即可。

因為 Gradle Kotlin DSL 是在 Gradle 5.0 之後才開始支援,所以我們先將 Gradle 升級到 5.0 以上,開啟檔案 gradle-wrapper.properties 來確認是否滿足 Gradle 5.0 版本以上。然後 Android Gradle Plugin 則是在 3.4 之後開始支援,所以也打開 Project-level build.gradle 確認 com.android.tools.build:gradle 版本是在 3.4 以上。

開始轉換 *.gradle 檔案,這邊有幾個規則我們會用到:

  • 把所有單引號 (‘xxx’) 換成雙引號 (“xxx “)
  • 在 Groovy 語法當中,下列兩種語法是相同的,可是在 Kotlin 是不同的寫法:
    • 設值 (Property assignment): applicationId "com.enginebai.project" → applicationId = "com.enginebai.project
    • 呼叫函式 (Function call): testImplementation "junit:junit:4.12" → testImplementation("junit:junit:4.12")

轉換 settings.gradle 且重新命名成 settings.gradle.kts:

include(":app")

轉換 Project-level build.gradle 檔案且重新命名成 build.gradle.kts:

// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
- ext.kotlin_version = "1.3.50"
repositories {
google()
jcenter()
}
dependencies {
- classpath "com.android.tools.build:gradle:3.5.1"
- classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
+ classpath("com.android.tools.build:gradle:3.5.1")
+ classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.3.50")
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
@@ -23,6 +22,8 @@ allprojects {
}
}
-task clean(type: Delete) {
- delete rootProject.buildDir
+tasks {
+ val clean by registering(Delete::class) {
+ delete(buildDir)
+ }
}

轉換 Module-level build.gradle 檔案且重新命名成 build.gradle.kts:

-apply plugin: "com.android.application"
-apply plugin: "kotlin-android"
-apply plugin: "kotlin-android-extensions"
+plugins {
+ id("com.android.application")
+ id("kotlin-android")
+ id("kotlin-android-extensions")
+}
android {
- compileSdkVersion 29
+ compileSdkVersion(29)
defaultConfig {
- applicationId "com.enginebai.project.base"
- minSdkVersion 23
- targetSdkVersion 29
- versionCode 1
- versionName "1.0"
- testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+ applicationId = "com.enginebai.project.base"
+ minSdkVersion(23)
+ targetSdkVersion(29)
+ versionCode = 1
+ versionName = "1.0"
+ testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
- release {
- minifyEnabled false
- proguardFiles getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro"
+ getByName("release") {
+ isMinifyEnabled = false
+ proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
}
}
}
dependencies {
+ implementation(fileTree("dir" to "libs", "include" to listOf("*.jar")))
+ implementation(Dependencies.kotlinStdLib)
+ implementation("androidx.appcompat:appcompat:1.1.0")
+ implementation("androidx.core:core-ktx:1.1.0")
+ implementation("androidx.constraintlayout:constraintlayout:1.1.3")
+ testImplementation("junit:junit:4.12")
+ androidTestImplementation("androidx.test:runner:1.2.0")
+ androidTestImplementation("androidx.test.espresso:espresso-core:3.2.0")
- implementation fileTree(dir: "libs", include: ["*.jar"])
- implementation Dependencies.kotlinStdLib
- implementation "androidx.appcompat:appcompat:1.1.0"
- implementation "androidx.core:core-ktx:1.1.0"
- implementation "androidx.constraintlayout:constraintlayout:1.1.3"
- testImplementation "junit:junit:4.12"
- androidTestImplementation "androidx.test:runner:1.2.0"
- androidTestImplementation "androidx.test.espresso:espresso-core:3.2.0"
}
app/build.gradle.kts

Step 3. 完全使用 Kotlin 來管理你的第三方程式庫

好,完成上面所有的轉換後,我們現在可以完全使用 Kotlin 來撰寫 *.gradle.kts 檔案,這時候我們回到 Step1. 步驟所建立 buildSrc 裡面的 Versions.kt / Dependencies.kt 檔案,開始新增我們所有使用到的版本和第三方程式庫,且取代所有的 *.gradle.kts 裡面的變數字串。

object Versions {
const val kotlin = "1.3.50"
const val androidX = "1.1.0"
const val junit = "4.12"
const val espresso = "3.2.0"
object Android {
const val sdk = 29
const val minSdk = 23
}
object App {
const val id = "com.enginebai.project.base"
const val versionCode = 1
const val versionName = "1.0.0"
}
}
object Dependencies {
const val gradlePlugin = "com.android.tools.build:gradle:3.5.1"
object Kotlin {
const val gradlePlugin = "org.jetbrains.kotlin:kotlin-gradle-plugin:${Versions.kotlin}"
const val stdLib = "org.jetbrains.kotlin:kotlin-stdlib-jdk7:${Versions.kotlin}"
}
object AndroidX {
const val appCompat = "androidx.appcompat:appcompat:${Versions.androidX}"
const val coreKtx = "androidx.core:core-ktx:${Versions.androidX}"
const val constraintLayout = "androidx.constraintlayout:constraintlayout:1.1.3"
}
object Test {
const val junit = "junit:junit:${Versions.junit}"
const val runner = "androidx.test:runner:1.2.0"
const val espressoCore = "androidx.test.espresso:espresso-core:${Versions.espresso}"
}
}
view raw Dependencies.kt hosted with ❤ by GitHub

最後全部取代更換完之後就完成全部的轉換:

Android Studio 會出現正確的語法提示和顏色

結語

大功告成!現在你可以開始使用 Kotlin 語法來做依賴管理,例如你要開始使用 RxJava,你就在 Version.kt 新增一個常數 const val rxjava = "2.2.5"(這只是舉例,請自行上網看最新版本號),Dependencies.kt 新增 const val rxjava = "io.reactivex.rxjava2:rxjava:${Versions.rxjava}",然後在 app/build.gradle.kts 新增 implement(Dependencies.rxjava) 然後 Gradle sync,搞定!!

這樣做就可以像平常在寫 Kotlin 程式一樣,你可以善用 IDE 的自動完成,可以重構(例如把 Dependencies.kt 的變數 rxjava = "..." 重新命名,build.gradle.kts 也會做對應的變更),之後當你專案規模變大時,特別是變成多個模組專案時,你就會非常的方便做你的依賴管理。

完整程式碼 ,歡迎給星 ⭐ https://github.com/enginebai/AndroidBase

10 thoughts on “Gradle Kotlin DSL

Add yours

  1. 轉換 settings.gradle 且重新命名成 build.gradle.kts
    應該是 settings.gradle.kts

    感謝分享~

    Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

Blog at WordPress.com.

Up ↑