雖然 Android 使用 Java 工具鏈作為其基礎是事實,但與純 Java 專案相比,仍然存在一些顯著差異;這些差異會影響 Task 的可快取性。對於包含 Kotlin 原始碼(因此使用 kotlin-android 外掛)的 Android 專案而言,更是如此。

消除歧義

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

為何使用建置快取?

建置快取可以顯著提升 Android 專案的建置效能,在許多情況下可提升 30-40%。Android Gradle 外掛提供的許多編譯和組裝 Task 都是可快取的,並且隨著每次新的迭代,會有更多 Task 變成可快取的。

更快的 CI 建置

CI 建置尤其受益於建置快取。典型的 CI 建置以 clean 開始,這表示預先存在的建置輸出會被刪除,並且組成建置的所有 Task 都不會是 UP-TO-DATE。但是,許多 Task 很可能在先前的 CI 建置中以完全相同的輸入執行過,從而填充了建置快取;來自先前執行的輸出可以安全地重複使用,從而顯著提高建置效能。

為本地開發重複使用 CI 建置

當您在一天開始時登入工作時,您的第一個 Task 通常是提取主分支,然後執行建置(無論您是否要求,Android Studio 都可能會執行後者)。假設對主分支的所有合併都在 CI 上建置(最佳實務!),您可以預期當天的第一個本地建置將享受更大的好處,這得益於 Gradle 的遠端快取。CI 已經建置了這個提交—為什麼您應該重新做這項工作?

切換分支

在本地開發期間,一天切換數次分支並不罕見。這會破壞 增量建置(即 UP-TO-DATE 檢查),但透過使用本地建置快取可以緩解此問題。您可能會在分支 A 上執行建置,這將填充本地快取。然後,您切換到分支 B 進行程式碼審查、協助同事或處理對開放 PR 的回饋。然後,您切換回分支 A 以繼續您的原始工作。當您下次建置時,先前在分支 A 上工作時建置的所有輸出都可以從快取中重複使用,從而可能節省大量時間。

Android Gradle 外掛

Android Studio 使用者應使用最新的 Android 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 專案中等效的測試 Task (AndroidUnitTest) 也是可快取的,因為 Android Gradle 外掛 3.6.0。

Instrumentation 測試執行(即 Espresso 測試)

Android Instrumentation 測試 (DeviceProviderInstrumentTestTask),通常稱為「Espresso」測試,也是不可快取的。Google Android 團隊也正在努力使此類測試可快取。請參閱 此問題

Lint

Android Lint Task 的使用者非常清楚使用它所付出的沉重效能代價,但也知道它對於尋找 Android 專案中的常見問題至關重要。目前,此 Task 不可快取。計劃在 Android Gradle 外掛 3.5 發布時使此 Task 可快取。這是始終使用最新版本 Android 外掛的另一個原因!

Fabric 外掛和 Crashlytics

Fabric 外掛用於整合 Crashlytics 崩潰報告工具(以及其他工具),非常受歡迎,但在建置過程中會產生一些沉重的效能代價。這是因為您的應用程式的每個版本都需要一個唯一識別碼,以便可以在 Crashlytics 儀表板中識別它。實際上,Crashlytics 的預設行為是將「每個版本」視為與「每次建置」同義。這會破壞 增量建置,因為每次建置都是唯一的。它也會破壞建置中某些 Task 的可快取性,原因相同。只需在「debug」建置中停用 Crashlytics 即可解決此問題。您可以在 Crashlytics 文件中找到相關說明。

如果您使用 Kotlin DSL,則參考文件中描述的修復程式無法直接運作;請參閱下面的解決方案。

Kotlin DSL

如果您使用 Kotlin DSL,則參考文件中描述的修復程式無法直接運作;這是由於 Kotlin DSL 與 Fabric 外掛之間的不相容性所致。根據 Kotlin DSL Primer 中的 此建議,有一個簡單的解決方案。

在您應用 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")