./gradlew dependencies 输出的是 gradle 实际解析并参与构建的依赖快照,需结合 --configuration runtimeclasspath 等参数查看版本选择详情,重点关注 (selected)、(requested)、(forced) 标记以识别隐式依赖与兼容性风险。

运行 ./gradlew dependencies 看实际解析的版本树
Gradle 默认用“最高版本胜出”策略解决冲突,但这个“胜出”不等于“可用”。./gradlew dependencies 输出的是最终参与构建的依赖快照,不是你写的那几行 implementation。
关键要看 --configuration runtimeClasspath 或 --configuration debugRuntimeClasspath 分支,尤其是带 (forced)、(requested)、(selected) 标记的节点。比如:
+--- com.squareup.okhttp3:okhttp:4.12.0 (selected) | \--- com.squareup.okhttp3:okhttp:3.14.9 (requested by com.some.lib:aar:2.1.0)
这说明:你没直接写 3.14.9,但它被某个 AAR 暗中拉进来了,而 Gradle 最终选了 4.12.0 —— 这就是风险点。
- 如果某库只在 3.14.x 中有
OkHttpClient.setConnectTimeout(),而 4.12.x 改成了 builder 模式,运行时就会NoSuchMethodError -
androidx.core:core出现两个不同 minor 版本(如 1.12.0 和 1.13.1),可能触发Duplicate class错误 - 注意
androidTestRuntimeClasspath和testRuntimeClasspath分支,测试依赖常引入和主流程不一致的 Guava、JUnit 等,容易埋雷
用 ./gradlew app:dependencyInsight 定位具体类的来源
当你发现某个类在运行时报 ClassNotFoundException 或方法找不到,别猜,直接查它到底从哪来:
./gradlew app:dependencyInsight --dependency "com.google.common.base.Preconditions" --configuration runtimeClasspath
输出会列出所有提供该类的模块,以及它们是如何被引入的(direct / transitive)、是否被 force/exclude 了。这是判断“是不是升级后某库悄悄删了这个类”的最快方式。
- 如果返回多个结果,且版本跨度大(比如 27.0-jre vs 32.0-android),基本可断定是 Guava 变体冲突
- 如果只返回一个结果,但版本明显低于你预期(比如你写了
4.12.0却显示4.9.3),说明有父 POM 或插件在暗中降级 - 加
--reverse参数可以反查“谁依赖了这个库”,对排查传递污染特别有用
升级前先跑 ./gradlew build --scan 对比差异
Gradle Build Scan 是免费且带时间戳的构建快照。升级依赖前执行一次,升级后立刻再执行一次,然后在 scans.gradle.com 上并排对比两份报告。
重点关注三个地方:
-
Dependency resolution 页面:看相同 group:artifact 是否 resolve 到不同 version;有没有新增
conflict resolution记录 -
Tasks 页面:是否有新出现的
checkDuplicateClasses或lintVitalRelease失败 - Build environment:确认 JDK、AGP、Kotlin 插件版本没被连带影响(比如升级一个 Kotlin 库,意外触发 KGP 版本升级)
很多兼容性问题其实不报错,只是 silently 替换了实现类——Build Scan 的 classes 视图能帮你发现这种“静默替换”。
对 AAR 和私有仓库依赖要额外验证二进制兼容性
AAR 包不像开源库那样有公开的 API diff 工具,它的兼容性必须靠实测。尤其当升级的是 com.android.tools.build:gradle 或 AGP 本身时:
- 检查 AAR 的
pom.xml里声明的compile和runtime依赖范围,确认它没硬编码旧版support-v4或已废弃的android.arch.* - 用
unzip -l your-lib.aar | grep "classes"看是否包含重复包名(比如同时含androidx/和android/support/) - 如果 AAR 来自内网 Nexus,确保它的 metadata 没被缓存污染:删掉本地
~/.gradle/caches/modules-2/metadata-下对应目录再 sync
最隐蔽的坑是:AAR 编译时用了 Java 8 的 invokedynamic 字节码,但你的项目设了 sourceCompatibility = JavaVersion.VERSION_1_7 —— 编译不报错,运行时直接 VerifyError。这种问题只能靠设备真机 + Logcat 抓 dalvikvm 日志定位。











