虽然 Android 确实使用 Java 工具链作为其基础,但与纯 Java 项目仍然存在一些显着差异;这些差异会影响任务的可缓存性。对于包含 Kotlin 源代码(因此使用该插件)的 Android 项目更是如此kotlin-android

消歧义

本指南是关于 Gradle 的构建缓存,但您可能也听说过Android 构建缓存。这些是不同的事情。 Android 缓存位于 Android 插件中某些任务的内部,最终将被删除以支持本机 Gradle 支持。

为什么要使用构建缓存?

构建缓存可以显着提高 Android 项目的构建性能,在许多情况下提高 30-40%。 Android Gradle 插件提供的许多编译和组装任务都是可缓存的,并且每次新迭代都会有更多任务被缓存。

更快的 CI 构建

CI 构建尤其受益于构建缓存。典型的 CI 构建以 开头clean,这意味着预先存在的构建输出将被删除,并且构成构建的任何任务都不会是UP-TO-DATE。然而,其中许多任务可能会在之前的 CI 构建中使用完全相同的输入来运行,从而填充构建缓存;先前运行的输出可以安全地重复使用,从而显着提高构建性能。

重用 CI 构建进行本地开发

当您在一天开始时登录工作时,您的第一个任务通常是拉取主分支,然后运行构建(无论您是否要求,Android Studio 可能会执行后者)。假设所有到 main 的合并都是基于 CI 构建的(最佳实践!),您可以期望今天的第一个本地构建能够通过 Gradle 的远程缓存享受到比典型的好处更大的好处。 CI 已经构建了这个提交——为什么你应该重新做这项工作?

切换分支

在本地开发过程中,每天多次切换分支的情况并不少见。这会破坏增量构建(即UP-TO-DATE检查),但通过使用本地构建缓存可以缓解此问题。您可以在分支 A 上运行构建,这将填充本地缓存。然后,您切换到分支 B 进行代码审查、帮助同事或处理开放 PR 的反馈。然后您切换回分支 A 继续原来的工作。当您下次构建时,之前在分支 A 上工作时构建的所有输出都可以从缓存中重用,从而可能节省大量时间。

Android Gradle 插件和 Gradle 构建工具

在优化构建时,您应该做的第一件事就是确保您使用最新的、稳定的、受支持的 Android Gradle 插件和 Gradle 构建工具版本。在撰写本文时,它们分别是 3.3.0 和 5.0。这些工具的每个新版本都包含许多性能改进,其中最重要的是构建缓存。

Java 和 Kotlin 编译

上面“缓存 Java项目”中的讨论在这里同样重要,但需要注意的是,对于包含 Kotlin 源代码的项目,Kotlin 编译器目前不支持像 Java 编译器那样的编译避免。

注解处理器和 Kotlin

上述针对纯 Java 项目的建议也适用于 Android 项目。但是,如果您将注释处理器(例如 Dagger2 或 Butterknife)与 Kotlin 和 kotlin-kapt 插件结合使用,您应该知道在 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 团队也在努力使此类测试可缓存。请看这个问题

皮棉

AndroidLint任务的用户非常清楚他们使用它所付出的沉重性能代价,但也知道它对于查找 Android 项目中的常见问题是必不可少的。目前,该任务不可缓存。该任务计划随着 Android Gradle Plugin 3.5 的发布而成为可缓存的。这是始终使用最新版本 Android 插件的另一个原因!

Fabric 插件和 Crashlytics

Fabric插件用于集成 Crashlytics 崩溃报告工具(等等),非常受欢迎,但在构建过程中会造成一些严重的性能损失这是因为应用程序的每个版本都需要有一个唯一的标识符,以便可以在 Crashlytics 仪表板中进行识别。实际上,Crashlytics 的默认行为是将“每个版本”视为“每个构建”的同义词。这会击败增量构建,因为每个构建都是唯一的。出于同样的原因,它还会破坏构建中某些任务的可缓存性。只需在“调试”版本中禁用 Crashlytics 即可解决此问题。您可以在Crashlytics 文档中找到相关说明。

如果您使用的是 Kotlin DSL,则参考文档中描述的修复不会直接起作用;请参阅下面的解决方法。

KotlinDSL

如果您使用的是 Kotlin DSL,则参考文档中描述的修复不会直接起作用;这是由于 Kotlin DSL 和 Fabric 插件之间不兼容造成的。基于Kotlin DSL 入门指南中的建议,有一个简单的解决方法。

fabric.gradle在应用插件的模块中创建一个文件io.fabric。该文件(称为脚本插件)应包含以下内容:

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

然后,在模块的build.gradle.kts文件中,应用此脚本插件:

构建.gradle.kts
apply(from = "fabric.gradle")