Gradle传递依赖解析:如何统一优先选择guava-jre而非guava-android?
这个问题我之前帮好几个开发者解决过——Guava的Android/JRE双版本分发确实容易让Gradle的依赖解析踩坑,你之前用固定版本替换的方式确实不够灵活,这里有几个更通用的方案,能让你不用每次版本升级都手动改配置:
方案1:动态替换所有Guava Android变体为JRE版本
通过Gradle的依赖解析策略,遍历所有依赖,自动将任何版本的Guava Android变体替换为对应的JRE版本,不管后续Guava升级到30、31还是更高版本都能适配:
configurations.all { resolutionStrategy.eachDependency { DependencyResolveDetails details -> def requested = details.requested // 匹配所有Guava的Android版本 if (requested.group == 'com.google.guava' && requested.name == 'guava' && requested.version.endsWith('-android')) { // 替换版本后缀为-jre def jreVersion = requested.version.replace('-android', '-jre') details.useTarget("com.google.guava:guava:${jreVersion}") } } }
这个逻辑的核心是动态处理版本号,不需要硬编码具体版本,完全适配Guava的版本迭代。
方案2:使用Guava BOM统一管理版本与变体
从Guava 28开始提供了BOM(Bill of Materials),导入JRE版本的BOM后,所有Guava相关依赖(包括传递依赖)都会自动使用指定的JRE版本,从根源上避免Android变体被选中:
dependencies { // 导入Guava JRE版本的BOM,这里可以替换为你需要的最新版本 implementation platform('com.google.guava:guava-bom:32.1.3-jre') // 直接声明Guava依赖,无需指定版本和变体,BOM会自动处理 implementation 'com.google.guava:guava' }
这种方式不仅解决了变体问题,还能帮你统一管理整个项目中的Guava版本,避免出现多版本冲突。
方案3:排除所有Android变体,直接声明JRE版本
如果你想更直接地控制依赖,可以先排除所有传递依赖中的Guava Android版本,再手动引入你需要的JRE版本:
configurations.all { // 用正则匹配所有以-android结尾的Guava版本并排除 exclude group: 'com.google.guava', module: 'guava', version: /.*-android/ } dependencies { // 直接引入指定版本的Guava JRE包 implementation 'com.google.guava:guava:32.1.3-jre' }
这个方式的好处是完全掌控依赖来源,不会有任何意外的Android变体混入你的依赖树。
补充说明:为什么会出现这个错误?
Guava为了兼容低版本Android,在-android变体中移除了一些JRE 8+才有的API(比如ImmutableList.toImmutableList()这个Stream Collector),而Gradle的依赖解析在遇到同时存在Android和JRE变体的传递依赖时,可能会因为优先级规则选中Android版本,导致你的非Android项目缺少必要的API。
内容的提问来源于stack exchange,提问作者Christian

