4. Gradle 构建缓存(Build Cache)与依赖缓存的区别:构建缓存 vs 依赖缓存、本地缓存 vs 远程缓存、启用远程构建缓存配置模板

在 AGP 升级过程中,许多开发者混淆了 Gradle 的构建缓存(Build Cache)和依赖缓存(Dependency Cache)。两者虽然都利用“缓存”提升构建速度,但存储内容、触发条件和生命周期截然不同。本章从原理、对比、本地/远程拓扑、配置模板四个层面厘清差异,并给出可直接落地的远程构建缓存配置。

4.1 构建缓存 vs 依赖缓存 —— 核心区别

维度构建缓存(Build Cache)依赖缓存(Dependency Cache)
缓存对象Task 输出产物(.class、.dex、APK、AAR 中间产物等)远程仓库下载的依赖文件(JAR、AAR、POM 等)
触发条件Task 输入(源码、资源、配置)未变依赖声明(GAV 坐标)未变
存储位置~/.gradle/caches/build-cache-*(本地)或远程 HTTP 服务器~/.gradle/caches/modules-2(固定路径)
生命周期由 Gradle 自身管理,按 LRU 淘汰,可手动清理除非用户手动删除或 Gradle 版本升级,几乎永久保留
跨项目共享通过远程构建缓存共享,无需重复构建只能本地副本共享,同一台机器不同项目共用 modules-2
AGP 版本影响Task 实现变更(如 AGP 8.x → 9.x)可能导致缓存失效依赖坐标不变即命中,与 AGP 版本无关
性能贡献跳过 Task 执行(编译、打包、签名等)跳过网络下载和解压(已缓存直接解压)
实战注意:AGP 升级后经常遇到“构建缓存未命中”问题,这是因为 Task 的缓存键(cache key)包含了 Gradle 插件版本、AGP 版本、构建工具版本等输入。此时应优先检查构建缓存,而不是怀疑依赖缓存 —— 依赖缓存通常不受版本变更影响。

4.2 本地缓存 vs 远程缓存

无论构建缓存还是依赖缓存,都可以分为本地和远程两层。下表总结各层的用途和风险。

缓存层级构建缓存依赖缓存
本地缓存~/.gradle/caches/build-cache-1,自动启用~/.gradle/caches/modules-2,自动启用
远程缓存需要显式配置 RemoteBuildCache(HTTP/HTTPS)依赖仓库本身即是远程缓存(Maven Central、Google Maven 等)
数据一致性远程构建缓存存储 Task 产物,需保证构建环境一致远程仓库依赖由发布者保证一致性
网络要求需要可靠的局域网或云端缓存服务器必须可访问外部依赖仓库
常见问题缓存键污染、过期缓存未清理仓库不可用、依赖被篡改(校验失败)

4.3 启用远程构建缓存 —— 配置模板

Gradle 远程构建缓存允许将 Task 输出推送到共享的 HTTP 服务器(如 Gradle Build Cache Node 或自定义缓存后端),供团队所有机器命中。以下配置放置在项目根目录的 gradle.properties 或 settings.gradle.kts/settings.gradle 中。

配置要点:
  • 远程缓存服务器必须支持 PUT/GET 且返回合理响应码(200/304)。
  • 建议同时启用本地缓存作为第一级缓存,避免频繁存取远程。
  • 生产环境务必开启 HTTPS 并配置鉴权。

Kotlin DSL — settings.gradle.kts

// 在 settings.gradle.kts 中配置远程构建缓存
buildCache {
    local {
        isEnabled = true                     // 启用本地构建缓存
        directory = File(rootDir, ".gradle/build-cache")
        removeUnusedEntriesAfterDays = 7     // 7天未使用自动清理
    }
    remote {
        url = uri("https://cache.company.com:8080/cache/")
        isEnabled = true
        isPush = true                        // 允许本机将缓存推送到远程
        // 可选鉴权配置
        credentials {
            username = "build-cache-user"
            password = System.getenv("GRADLE_CACHE_PASSWORD") ?: ""
        }
    }
}

Groovy DSL — settings.gradle

// settings.gradle
buildCache {
    local {
        enabled = true
        directory = "${rootDir}/.gradle/build-cache"
        removeUnusedEntriesAfterDays = 7
    }
    remote(HttpBuildCache) {
        url = 'https://cache.company.com:8080/cache/'
        enabled = true
        push = true
        credentials {
            username = 'build-cache-user'
            password = System.getenv('GRADLE_CACHE_PASSWORD') ?: ''
        }
    }
}
常见错误:
  • 忘记在 settings.gradle 中配置远程缓存,而只在 build.gradle 中引用 — 构建设置必须放在 settings 层。
  • 远程缓存服务器不可达时,构建会降级为仅本地缓存,但不会报错中断,导致团队误以为命中远程。
  • 同一项目在不同机器使用不同的 JDK 或 AGP 版本会导致缓存键不同,远程命中率为 0 — 应统一开发环境。

4.4 整体缓存拓扑关系图

下图展示了构建缓存与依赖缓存在一次构建中的位置和交互流程,以及本地/远程各层如何协作。

构建缓存与依赖缓存拓扑(含本地/远程层级) 源代码 / 资源变更 Gradle Task 执行 构建缓存(本地) ~/.gradle/caches/build-cache-* 构建缓存(远程) HTTP 缓存服务器 依赖缓存(本地) ~/.gradle/caches/modules-2 远程依赖仓库 Maven / JCenter / 自建 输出产物 虚线 = 远程查询/下载路径 实线 = 本地缓存命中/任务执行

4.5 调试与验证缓存策略

启用远程构建缓存后,通过以下方式验证是否生效:

  • 构建日志:添加 --info 查看 Task cache store 来源。命中远程时会显示 Remote,本地命中显示 Local。
  • 清理实验:./gradlew clean 后第二次构建,若 Task 输出全部 FROM-CACHE 则缓存工作正常。
  • 远程监控:检查缓存服务器的 PUT/GET 请求日志,确认本机是否有推拉动作。
性能建议:若团队使用 CI/CD,建议 CI 节点同时开启push = true,开发者节点设为push = false(只读远程),避免多人同时写入导致缓存碎片。