第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 动态指定构建缓存存储位置。利用此特性,我们可以在不破坏原有缓存的前提下,将当前有效缓存“导出”到另一个目录,作为备份快照。操作流程:
- 获取当前项目使用的Gradle版本和AGP版本(用于标记快照)。
- 创建备份目录,如
/backup/cache-snapshot-2025-04-08。 - 运行一次
gradle clean assembleDebug --build-cache-dir /backup/cache-snapshot-2025-04-08。 - 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 验证步骤:确认缓存快照可用性
- 创建一个干净的新工作目录,将备份的压缩包解压并复制到
~/.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/
- 然后对原项目执行一次增量构建(不执行
clean):
cd /path/to/project
gradle assembleDebug --build-cache
- 观察构建时间是否与升级前接近(差异 ≤ 10% 即视为有效快照)。如果构建时间明显增加,说明备份缓存不完整或已损坏,需重新备份。
实战要点:对于大型项目(缓存总容量 > 5GB),推荐同时保留一份“未压缩的软链接备份”和一份“压缩存档”,前者用于日常回滚,后者用于长期归档。使用
--build-cache-dir导出的缓存不包含配置缓存,需单独备份configuration-cache。