依赖校验是构建失败前的最后一道防线,Gradle 7.4+ 默认启用但静默跳过;需通过./gradlew --write-verification-metadata sha256,sha512自动生成gradle/verification-metadata.xml,并提交至版本库以确保CI校验生效。

依赖校验不是可选项,而是构建失败前的最后一道防线
Gradle 从 7.4 起默认启用依赖验证(Dependency Verification),但gradle/verification-metadata.xml文件不存在时,它会静默跳过——你不会收到任何警告,直到某天 CI 构建突然拉下被篡改的 okhttp-4.12.0.jar,引发 NoClassDefFoundError 或签名不匹配异常。校验不是“防黑客”,而是防镜像源劫持、CDN 缓存污染、本地仓库误覆盖这类真实发生的供应链事故。
生成 verification-metadata.xml 的正确姿势
别手写 XML,也别复制网上过时的 schema 地址。Gradle 8.6+ 要求使用 https://schema.gradle.org/dependency-verification/dependency-verification-1.4.xsd(注意是 1.4,不是 1.3)。最稳妥方式是让 Gradle 自动生成:
./gradlew --write-verification-metadata sha256,sha512 --no-daemon
这条命令会:
- 强制解析所有依赖(包括 testRuntimeClasspath、annotationProcessor 等隐式配置)
- 为每个 JAR/AAR/POM 文件生成 SHA-256 和 SHA-512 校验和
- 自动写入
gradle/verification-metadata.xml,含完整 namespace 和 xsi:schemaLocation - 跳过已签名的依赖(如 Maven Central 上带
.asc的包),除非你显式开启true
生成后务必 git add gradle/verification-metadata.xml —— 没提交,CI 就不校验。
校验失败时常见错误信息与定位方法
典型报错长这样:
Verification failed for artifact 'com.squareup.okhttp3:okhttp:4.12.0' Expected checksum 'a1b2c3...' but was 'd4e5f6...'
这时不要急着删缓存或重下。先确认三件事:
-
./gradlew dependencies --configuration runtimeClasspath | grep okhttp看实际解析出的坐标是否和verification-metadata.xml中记录的一致(尤其注意 classifier 是否缺失,比如okhttp-4.12.0-android.jar和okhttp-4.12.0.jar是两个不同 artifact) - 检查
~/.gradle/caches/modules-2/files-2.1/com.squareup.okhttp3/okhttp/4.12.0/下文件是否被其他进程(如杀毒软件、IDE 后台扫描)临时锁定导致读取异常 - 确认没在
build.gradle里用force = true或exclude group:干扰了原始依赖图,这会导致 Gradle 解析出的文件和元数据不匹配
签名验证(signatures)为什么常被关掉?
不是因为它不重要,而是因为现实太骨感:
- AndroidX 绝大多数 AAR 不提供签名(
.asc文件),开verify-signatures=true直接构建失败 - 公司私有 Nexus 仓库通常不配 GPG 签名,但又必须校验完整性 —— 这时只保留
sha256是合理妥协 - Gradle 对签名链验证较严格:若中间证书过期、公钥服务器不可达(如 keyserver.ubuntu.com 被墙),整个构建中断,而校验和是纯本地计算,稳定得多
真正需要签名验证的场景,通常是对接金融级合规要求(如 SOC2、等保三级),且所有依赖都来自经认证的发布者(如 Spring 官方 repo、Google Maven)。普通项目优先保校验和,签名留作灰度阶段验证手段。
校验和是底线,签名是高线;没校验和,连底线都守不住。别把 verification-metadata.xml 当成一次性配置,它得随每次依赖升级一起更新 —— 否则你锁住的就不是安全,而是过期的信任。











