雖然 Android 確實使用 Java 工具鏈作為其基礎,但與純 Java 專案仍有一些顯著差異;這些差異會影響工作快取能力。對於包含 Kotlin 原始碼(因此使用 kotlin-android 外掛程式)的 Android 專案來說,情況更是如此。

消除歧義

本指南是關於 Gradle 的建置快取,但您可能也聽過 Android 建置快取。這些是不同的東西。Android 快取是 Android 外掛程式中特定工作內部的快取,最終將會被原生 Gradle 支援所取代。

為何使用建置快取?

建置快取可以顯著提升 Android 專案的建置效能,在許多情況下提升 30-40%。Android Gradle 外掛程式提供的許多編譯和組建工作都是可快取的,而且隨著每次新的反覆運算,可快取的工作會越來越多。

更快的 CI 建置

CI 建置特別受益於建置快取。典型的 CI 建置從 clean 開始,這表示已存在的建置輸出會被刪除,而且組成建置的任何工作都不會是 UP-TO-DATE。但是,這些工作中有許多可能在先前的 CI 建置中使用完全相同的輸入執行過,並填入建置快取;先前執行產生的輸出可以安全地重複使用,進而大幅提升建置效能。

重複使用 CI 建置進行在地端開發

當您在一天開始時登入工作時,您的第一個任務通常是提取主分支,然後執行建置(無論您是否要求,Android Studio 可能會執行後者)。假設所有合併到主分支的內容都在 CI 中建置(最佳做法!),您可以預期這一天的第一個本機建置會透過 Gradle 的遠端快取享有比平常更大的好處。CI 已建置此提交,為什麼您要重新執行該工作?

切換分支

在進行本機開發期間,每天切換分支數次並不少見。這會影響增量建置(即 UP-TO-DATE 檢查),但此問題可透過使用本機建置快取來減輕。您可以在分支 A 上執行建置,這會填入本機快取。然後,您切換到分支 B 來進行程式碼檢閱、協助同事或處理開放式公關的意見回饋。然後,您切換回分支 A 以繼續您的原始工作。當您下次建置時,所有先前在分支 A 上工作時建置的輸出都可以從快取中重複使用,這可能會節省大量時間。

Android Gradle 外掛程式和 Gradle 建置工具

在進行建置最佳化時,您應該始終執行的第一件事是確保您使用的是 Android Gradle 外掛程式和 Gradle 建置工具的最新穩定支援版本。在撰寫本文時,它們分別是 3.3.0 和 5.0。這些工具的每個新版本都包含許多效能改善,其中最不重要的是建置快取。

Java 和 Kotlin 編譯

上述「快取 Java 專案」中的討論在此同樣相關,但對於包含 Kotlin 原始碼的專案,Kotlin 編譯器目前不支援編譯避免,而 Java 編譯器則支援。

註解處理器和 Kotlin

上述建議適用於純 Java 專案,也適用於 Android 專案。不過,如果你在 Kotlin 和 kotlin-kapt 外掛程式中使用註解處理器(例如 Dagger2 或 Butterknife),你應該知道在 Kotlin 1.3.30 之前,kapt 預設不會快取

你可以選擇加入(建議這麼做),方法是在建置指令碼中加入下列內容

build.gradle.kts
pluginManager.withPlugin("kotlin-kapt") {
    configure<KaptExtension> { useBuildCache = true }
}
build.gradle
plugins.withId("kotlin-kapt") {
    kapt.useBuildCache = true
}

單元測試執行

與純 Java 專案中的單元測試不同,Android 專案中對應的測試任務 (AndroidUnitTest) 無法快取。Google 團隊正在努力讓這些測試可快取。請參閱 此問題

工具測試執行(例如 Espresso 測試)

Android 工具測試 (DeviceProviderInstrumentTestTask),通常稱為「Espresso」測試,也無法快取。Google Android 團隊也正在努力讓此類測試可快取。請參閱 此問題

Lint

Android 的 Lint 任務使用者非常清楚使用此任務會造成極大的效能損失,但也知道它對於找出 Android 專案中的常見問題不可或缺。目前,此任務無法快取。此任務預計會在 Android Gradle 外掛程式 3.5 發布時可快取。這也是始終使用最新版本的 Android 外掛程式的另一個原因!

Fabric 外掛程式和 Crashlytics

用於整合 Crashlytics 崩潰回報工具(以及其他工具)的 Fabric 外掛程式非常受歡迎,但會在建置過程中造成一些龐大的效能損失。這是因為應用程式的每個版本都需要一個唯一識別碼,才能在 Crashlytics 儀表板中識別。實際上,Crashlytics 的預設行為是將「每個版本」視為「每個建置」的同義詞。這會破壞 增量建置,因為每個建置都會是唯一的。它也會破壞建置中某些任務的快取能力,原因相同。這可以用在「偵錯」建置中停用 Crashlytics 來修復。您可以在 Crashlytics 文件 中找到相關說明。

如果您使用 Kotlin DSL,則所引用的文件說明中的修復無法直接運作;請參閱下方以取得解決方法。

Kotlin DSL

如果您使用 Kotlin DSL,則所引用的文件說明中的修復無法直接運作;這是因為 Kotlin DSL 與 Fabric 外掛程式之間不相容。根據 Kotlin DSL 入門手冊中的 此建議,有一個簡單的解決方法。

在套用 io.fabric 外掛程式的模組中建立一個檔案 fabric.gradle。此檔案(稱為腳本外掛程式)應具有下列內容

fabric.gradle
plugins.withId("com.android.application") { // or "com.android.library"
    android.buildTypes.debug.ext.enableCrashlytics = false
}

然後,在模組的 build.gradle.kts 檔案中套用此腳本外掛程式

build.gradle.kts
apply(from = "fabric.gradle")