4、依赖库版本冲突(com.android.support 与 androidx)

这个话题,说白了就是 Android 开发史上最头痛的「新旧交替」问题。我记得 2019 年那会儿,Google 大力推广 AndroidX,很多第三方库还没跟上。我接手的项目里,经常遇到这样的报错:

All com.android.support libraries must use the exact same version specification
(mixing versions can lead to runtime crashes).
Found versions 28.0.0, 27.1.0

或者更直接的:

Cannot have both 'com.android.support:appcompat-v7:28.0.0' and 
'androidx.appcompat:appcompat:1.0.0' in the same project.

这两种错误,本质上是一个根源:你的项目里同时混用了旧的 Support 库和新的 AndroidX 库。Gradle 在解析依赖树时发现冲突,直接罢工。你想想看,一个依赖是 Support,另一个依赖又引入了 AndroidX,两套体系完全不兼容,肯定炸。

为什么会出现这种冲突?

多数情况下不是你自己直接写的依赖有问题,而是第三方库间接引入的。举个例子:

  • 你引入了库 A,它内部依赖 com.android.support:appcompat-v7:28.0.0
  • 你引入了库 B,它已经迁移到了 AndroidX,依赖 androidx.appcompat:appcompat:1.2.0
  • 项目本身也使用了 androidx.core:core:1.3.0

这时候 Support 和 AndroidX 共存,构建就失败。我在项目中就遇到过:一个第三方支付 SDK 还在用 Support 28,而项目其他部分都迁移到了 AndroidX,折腾了我一整天。

如何快速定位冲突来源?

别慌,Gradle 给了我们一把利器——依赖树。我个人习惯用这个命令:

./gradlew :app:dependencies --configuration debugCompileClasspath

如果你只想看某个具体库的冲突,可以用:

./gradlew :app:dependencyInsight --dependency appcompat --configuration debugCompileClasspath

输出会告诉你每个依赖是从哪条路径引入的。比如我上次就发现:

com.android.support:appcompat-v7:28.0.0 (via: some-phone-lib:1.2.0 -> support-compat:28.0.0)
androidx.appcompat:appcompat:1.2.0 (via: project :app)

嗯,这样根源就一目了然了。

小技巧: 用 --scan 参数可以生成构建扫描报告,在浏览器里可视化依赖树,更直观。但注意不要提交到公共仓库。

解决方案:三选一

针对 Support 和 AndroidX 混用的冲突,我总结出三个有效方案,你可以根据项目情况选一个。

方案 适用场景 核心操作
方案A:全量迁移到 AndroidX 项目已接新,旧库有迁移版本 启用 android.useAndroidX=true,手动替换所有 Support 依赖
方案B:强制统一 Support 版本 遗留项目,第三方库未迁移 在 dependencies 中用 force 或 constraints 固定版本
方案C:排除冲突传递依赖 只有一两个库引入冲突 使用 exclude 或 transitive = false 孤立冲突源

方案A 详细做法

在 gradle.properties 中添加:

android.useAndroidX=true
android.enableJetifier=true

然后手动把所有 com.android.support 改成 androidx 对应包名。Jetifier 会自动处理第三方库中的 Support 引用。

方案B 详细做法

在 build.gradle 中用 force 强制指定版本:

configurations.all {
    resolutionStrategy {
        force 'com.android.support:appcompat-v7:28.0.0'
        force 'com.android.support:support-compat:28.0.0'
        // 其他 Support 库
    }
}

这样所有 Support 库都会被统一到 28.0.0,避免版本混合。但注意:这不能解决与 AndroidX 的共存问题——如果你同时有 AndroidX 库,依然会炸。

方案C 详细做法

在引入具体依赖时排除冲突模块:

implementation('com.example:some-phone-lib:1.2.0') {
    exclude group: 'com.android.support'
}

如果你确定这个库不需要 Support,可以直接排除整个 group。但以防万一,最好先测试功能是否正常。

注意: 排除依赖可能引起运行时崩溃,特别是如果第三方库内部用了 Support 类。我曾经因为排除后少了一个 FragmentActivity 的依赖,导致 UI 直接闪退。所以排除前务必做依赖分析。

我的避坑指南

  • 不要手动改包名—— 用 Android Studio 的 Refactor → Migrate to AndroidX 功能,虽然不完美,但比手动替换安全。
  • 优先升级第三方库—— 查一下你依赖的第三方库是否有 AndroidX 版本,哪怕大版本升级也在所不惜。我见过有人死守着旧版库,结果卡在 Support 坑里出不来。
  • 多做增量迁移—— 如果项目很大,可以分批迁移模块,用 flavor 或 buildType 区分,先迁移核心模块测试。

知识结构图

下面这张图梳理了 Support 与 AndroidX 冲突的完整链路:

Support 与 AndroidX 依赖冲突分析流程 多个依赖库分别引入 Support 和 AndroidX AGP 构建时检测到冲突 → 报错 ./gradlew dependencies dependencyInsight 构建扫描 --scan 定位到冲突的第三方库与传递路径 迁移到 AndroidX 统一 Support 版本 排除冲突传递依赖 ⚠️ 建议优先迁移 AndroidX,长期维护成本最低

核心要点总结:

  • 冲突本质:Support 与 AndroidX 的类和方法签名不同,不能共存于同一进程。
  • 排查利器:dependencies 和 dependencyInsight 命令。
  • 三种解法:迁移、统一、排除,按场景选择。
  • 最佳实践:新项目直接上 AndroidX,旧项目尽快迁移。

嗯,就这样。依赖冲突其实不可怕,只要你会看依赖树,再配合工具分析,一般半小时内就能搞定。我遇到过最极端的案例是某个老项目有 40 多个 module,层层依赖像蛛网一样,最后靠 dependencyInsight 一个个查,花了半天。但搞清楚之后,稳定运行到现在都没出过幺蛾子。