第4章 AGP版本升级前的缓存快照备份:使用Gradle的--build-cache-dir参数导出当前缓存、备份gradle缓存目录的脚本与操作

4.1 为什么需要缓存快照备份

AGP版本升级时,构建缓存键生成规则或缓存格式可能发生变化。升级后旧缓存失效,一旦新版本存在问题需要回滚,一份完整的缓存快照能让你立即恢复到升级前的构建速度,避免全量重编。备份的三种常见策略如下表:

策略适用场景风险等级
直接复制缓存目录快速暂存,无配置变更低
使用--build-cache-dir导出需隔离验证新旧缓存中
编写自动化脚本CI/CD环境或团队规范低
建议:升级前至少采用“直接复制目录”+“使用--build-cache-dir导出”双重备份,以保证可回滚至完全一致的构建环境。

4.2 AGP缓存机制与备份目标

AGP构建缓存主要分为:

  • 构建缓存(Build Cache):默认路径 ~/.gradle/caches/build-cache-1,存放编译输出、AAR打包等中间产物。
  • 配置缓存(Configuration Cache):路径 ~/.gradle/caches/configuration-cache,存放配置阶段序列化数据。
  • 项目级缓存:$PROJECT_ROOT/.gradle 内的任务缓存和资源池。

备份快照的核心是完整保留所有缓存目录,尤其 build-cache-1 和 configuration-cache 两个文件夹。

4.3 使用--build-cache-dir参数导出当前缓存

Gradle 允许通过 --build-cache-dir 动态指定构建缓存存储位置。利用此特性,我们可以在不破坏原有缓存的前提下,将当前有效缓存“导出”到另一个目录,作为备份快照。操作流程:

  1. 获取当前项目使用的Gradle版本和AGP版本(用于标记快照)。
  2. 创建备份目录,如 /backup/cache-snapshot-2025-04-08。
  3. 运行一次 gradle clean assembleDebug --build-cache-dir /backup/cache-snapshot-2025-04-08。
  4. Gradle会将所有可缓存的输出写入新目录,同时原缓存不受影响。
注意:此方法要求项目能成功构建一次,且clean会清空本地编译产物,但不会清除build-cache-dir。如果项目无法构建,请改用直接复制目录的脚本。

4.4 备份gradle缓存目录的脚本与操作

以下Bash脚本自动备份Gradle用户目录缓存和项目的.gradle目录,并支持压缩与时间戳标记:

#!/bin/bash
# backup_gradle_cache.sh - 备份AGP升级前的构建缓存
set -e

BACKUP_ROOT="/tmp/cache-backups"
TIMESTAMP=$(date +"%Y%m%d_%H%M%S")
BACKUP_DIR="${BACKUP_ROOT}/gradle-cache-snapshot-${TIMESTAMP}"
GRADLE_USER_HOME="${GRADLE_USER_HOME:-$HOME/.gradle}"
PROJECT_DIR="${1:-.}"

echo "=== 备份开始: $TIMESTAMP ==="
mkdir -p "$BACKUP_DIR"

# 1. 复制用户级缓存(构建缓存+配置缓存)
rsync -a --delete \
  "$GRADLE_USER_HOME/caches/build-cache-1" \
  "$BACKUP_DIR/user-build-cache/" 2>/dev/null || echo "警告: 构建缓存目录不存在"

rsync -a --delete \
  "$GRADLE_USER_HOME/caches/configuration-cache" \
  "$BACKUP_DIR/user-config-cache/" 2>/dev/null || echo "警告: 配置缓存目录不存在"

# 2. 复制项目级缓存
rsync -a --delete \
  "$PROJECT_DIR/.gradle" \
  "$BACKUP_DIR/project-gradle-cache/"

# 3. 记录当前AGP和Gradle版本
echo "AgpVersion: $(grep 'com.android.tools.build' "$PROJECT_DIR/build.gradle" 2>/dev/null | head -1)" > "$BACKUP_DIR/versions.txt"
echo "GradleVersion: $(gradle --version 2>/dev/null | grep 'Gradle ' | head -1)" >> "$BACKUP_DIR/versions.txt"

# 4. 打包压缩(可选)
tar -czf "${BACKUP_DIR}.tar.gz" -C "$BACKUP_ROOT" "gradle-cache-snapshot-${TIMESTAMP}"
rm -rf "$BACKUP_DIR"

echo "=== 备份完成: ${BACKUP_DIR}.tar.gz ==="

运行方式:

chmod +x backup_gradle_cache.sh
./backup_gradle_cache.sh /path/to/your/project

4.5 构建日志分析与验证

备份完成后,检查日志中是否出现以下关键信息:

  • 备份目录大小:du -sh ${BACKUP_ROOT}/gradle-cache-snapshot-*.tar.gz
  • 版本记录文件:cat ${BACKUP_ROOT}/versions.txt 确认AGP版本号与预期一致。
  • 完整性校验:使用 tar -tzf backup.tar.gz 列出文件结构,确保关键目录(build-cache-1、configuration-cache)存在。

4.6 常见缓存兼容性问题与调试方案

问题原因调试方法
备份后缓存无法恢复使用权限不足或路径包含符号链接使用ls -la检查文件权限,添加--copy-links参数
--build-cache-dir导出时构建失败依赖损坏或网络问题先执行gradle dependencies解决,再重试导出
备份文件过大(> 2GB)缓存中包含了无用增量在脚本中添加--exclude='*.tmp'或使用--max-size=100M

4.7 性能优化建议

  • 增量备份:使用 rsync --link-dest 保留硬链接,只备份差异部分。
  • 并行压缩:将 tar -czf 替换为 tar -cf - | pigz -p 4 > backup.tar.gz,利用多核CPU。
  • 避免备份无变化的任务缓存:在脚本中只备份 build-cache-1 和 configuration-cache,忽略modules-2等依赖仓库。

4.8 验证步骤:确认缓存快照可用性

  1. 创建一个干净的新工作目录,将备份的压缩包解压并复制到 ~/.gradle/caches/:
mkdir -p ~/test-cache-restore
cd ~/test-cache-restore
tar -xzf /tmp/cache-backups/gradle-cache-snapshot-*.tar.gz
cp -r gradle-cache-snapshot-*/user-build-cache/build-cache-1 ~/.gradle/caches/
cp -r gradle-cache-snapshot-*/user-config-cache/configuration-cache ~/.gradle/caches/
  1. 然后对原项目执行一次增量构建(不执行clean):
cd /path/to/project
gradle assembleDebug --build-cache
  1. 观察构建时间是否与升级前接近(差异 ≤ 10% 即视为有效快照)。如果构建时间明显增加,说明备份缓存不完整或已损坏,需重新备份。
AGP升级前缓存快照备份流程图 1. 确定缓存目录 2. 选择备份方式 直接复制目录 --build-cache-dir导出 3. 执行构建任务 4. 压缩+版本标记 5. 验证快照完整性 备份注意事项: • 确保磁盘剩余空间 > 2倍缓存大小 • 备份前停止所有Gradle守护进程 • 使用版本号标记快照,便于回滚 • 验证时优先选用小项目单元测试 • 备份脚本应纳入版本控制
实战要点:对于大型项目(缓存总容量 > 5GB),推荐同时保留一份“未压缩的软链接备份”和一份“压缩存档”,前者用于日常回滚,后者用于长期归档。使用--build-cache-dir导出的缓存不包含配置缓存,需单独备份configuration-cache。