虽然 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 以进行代码审查、帮助同事或处理有关开放 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 项目中等效的测试任务 (AndroidUnitTest) 自 Android Gradle Plugin 3.6.0 起也是可缓存的。

Instrumentation 测试执行(即 Espresso 测试)

Android instrumentation 测试 (DeviceProviderInstrumentTestTask),通常称为“Espresso”测试,也是不可缓存的。Google Android 团队也在努力使此类测试可缓存。请参阅 此问题

Lint

Android Lint 任务的用户非常清楚他们为使用它而付出的巨大性能代价,但也知道它对于查找 Android 项目中的常见问题是不可或缺的。目前,此任务不可缓存。此任务计划在 Android Gradle Plugin 3.5 版本中实现可缓存。这是始终使用最新版本 Android 插件的另一个原因!

Fabric 插件和 Crashlytics

Fabric 插件用于集成 Crashlytics 崩溃报告工具(以及其他工具),非常受欢迎,但在构建过程中会带来一些沉重的性能损失。这是因为您的应用程序的每个版本都需要一个唯一的标识符,以便可以在 Crashlytics 仪表板中识别它。实际上,Crashlytics 的默认行为是将“每个版本”视为与“每次构建”同义。这破坏了 增量构建,因为每次构建都是唯一的。这也破坏了构建中某些任务的可缓存性,原因相同。只需在“debug”构建中禁用 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")