启用 Gradle 构建缓存配置
Gradle 构建缓存能够复用上一次构建的输出产物(如编译后的 class 文件、AAR 包、DEX 产物),避免相同输入下重复执行任务。对于大型 Android 项目,配置正确的缓存策略可将增量构建时间降低 50%~80%。本章将涵盖本地缓存、远程缓存、缓存键定制与缓存清理的完整实践。
1. 构建缓存原理与类型
Gradle 使用缓存键(Cache Key)匹配任务输入。当任务的输入(源码、资源、JDK 版本、插件版本、构建脚本等)完全一致时,缓存命中,任务跳过执行直接输出上次结果。
| 缓存类型 | 存储位置 | 共享范围 | 典型场景 |
|---|---|---|---|
| 本地缓存 | ~/.gradle/caches/build-cache-1 | 本机所有项目 | 单人开发,切换分支或反复清理项目 |
| 远程缓存 | HTTP 服务器(如 Nginx、S3) | 团队 / CI 节点 | CI 机器与开发者共享编译产物 |
推荐策略:开发环境启用本地缓存 + 远程只读(pull),CI 环境启用远程读写(push)。避免开发机写入不稳定网络导致远程缓存污染。
2. 配置 buildCache(全局 + 项目级)
全局配置文件 ~/.gradle/init.gradle 或 ~/.gradle/init.d/ 下的脚本会对所有项目生效;项目级配置放在 settings.gradle 中。
// settings.gradle 示例
buildCache {
local {
enabled = true
// 缓存路径(可选,默认 ~/.gradle/caches/build-cache-1)
directory = new File(rootDir, '.build-cache')
// 缓存保留策略:按大小(MB)或保留天数
removeUnusedEntriesAfterDays = 30
// 禁用本地缓存推送远程(开发机)
push = false
}
remote(HttpBuildCache) {
enabled = true
url = 'https://cache.example.com/'
// CI 或授权令牌
username = System.getenv('CACHE_USER')
password = System.getenv('CACHE_PASS')
// 开发机只拉取不推送
push = System.getenv('CI')?.toBoolean() ?: false
}
}
注意:远程缓存 url 必须以
/ 结尾;若使用自签名 HTTPS,需在 Gradle 启动参数添加 -Dorg.gradle.cache.tls.trustStore。
3. 缓存键策略(Cache Key Customization)
默认缓存键基于任务输入的文件内容哈希(NormalizedPathInputs)+ 任务类型 + 插件版本。当需要忽略某些无关输入(如时间戳、构建机器环境变量)时,可定制缓存键。
// 在 build.gradle.kts 中为特定任务排除无关输入
tasks.withType().configureEach {
outputs.cacheIf { true }
inputs.property("gradleVersion", gradle.gradleVersion)
.withNormalizer(ClassLoaderNormalizer::class.java)
}
// 禁用某个任务的缓存(例如代码生成器每次必须执行)
tasks.named("processResources") {
outputs.cacheIf { false }
}
常用缓存键调整手段:
- 文件路径归一化:
inputs.file(...).withNormalizer(PathNormalizer)忽略路径差异。 - 忽略环境变量:在
gradle.properties中设置org.gradle.caching=false可全局关闭。 - 自定义 cacheKey:通过
@CacheableTask注解或实现HasCustomActions接口。
4. 清理缓存
缓存堆积可能导致磁盘空间膨胀,或旧缓存包含错误产物。常用清理方法:
# 1. 手动删除整个本地缓存目录
rm -rf ~/.gradle/caches/build-cache-1
# 2. Gradle 内置清理(按保留策略)
./gradlew cleanBuildCache
# 3. 通过 init script 控制保留天数(见 settings.gradle 示例)
# 4. 远程缓存清理:由服务端管理(如配置保留最近 90 天的缓存条目)
实践建议:在 CI 流水线结尾执行
cleanBuildCache 配合 removeUnusedEntriesAfterDays = 7,避免缓存膨胀导致磁盘满;同时在开发机保留 30 天以支持分支切换。
5. 构建缓存工作流程
下图展示了缓存命中与未命中的完整路径:
6. 常见错误与排查
| 现象 | 原因 | 解决 |
|---|---|---|
| 本地缓存永远不命中 | 缓存键包含路径或时间戳 | 启用 NormalizedPathInputs 或移除 instantRun/buildId 输入 |
| 远程缓存上传失败 | URL 配置错误或证书问题 | 检查 url 末尾斜杠,添加 -Dorg.gradle.cache.tls.trustStore |
| 缓存占用空间巨大 | 未设置 removeUnusedEntriesAfterDays | 在 buildCache 块中设置保留策略 |
| Android 资源合并不缓存 | AGP 部分任务默认不缓存 | 通过 //no-cache 注解或升级 AGP 版本 |
性能优化点:在多模块项目中使用并行缓存下载(
org.gradle.caching.parallel=true),同时限制并发连接数(org.gradle.caching.local.parallelism=4)避免网络拥堵。