关于 OkHttp 依赖冲突问题的解决过程

博客搬家」 原地址: CSDN 原发表时间: 2016-11-18

OkHttp 是一个流行的开源网络请求库。许多第三方库的底层都是使用 OkHttp 实现网络请求,所以 OkHttp 相关的依赖冲突问题就变得很难避免,下文是我所遇到的一次关于 OkHttp 的依赖冲突问题,通过对 Gradle 工具及 Android Studio 的灵活使用,解决了此问题。@H_403_5@

1. 关于 OkHttp 的依赖冲突

我的项目中, build.gradle 文件中设置的主要依赖:@H_403_5@

dependencies {
    compile 'com.android.support:appcompat-v7:24.0.0'
    compile 'cn.bmob.android:bmob-sdk:3.5.2'
    compile 'com.squareup.okhttp3:okhttp:3.4.2'
    compile 'com.facebook.fresco:imagepipeline-okhttp3:0.12.0'
    compile 'com.facebook.fresco:fresco:0.12.0'
}

在写该 App 的过程中,出现了较为诡异的情况:@H_403_5@

  • 使用 Run 'app' 命令可以在 Android 6.0「API 23」环境中成功运行 App
  • 使用 Run 'app' 命令针对 Android 4.4「API 19」环境的虚拟机,进行 Gradle 构建时报错
  • 使用「Generate Signed APK」,在进行 Gradle 构建时报错
  • 在 cmd 或 Windows PowerShell 中执行如下 Gradle 指令:
gradle clean
gradle build

报错,所报错误分别如下 :@H_403_5@

Error:Error converting bytecode to dex:
Cause: com.android.dex.DexException: Multiple dex files define Lokhttp3/Address;

Error:Execution Failed for task ':app:transformClassesWithDexForDebug'.
> com.android.build.api.transform.TransformException: com.android.ide.common.process.ProcessException: java.util.concurrent.ExecutionException: java.lang.UnsupportedOperationException
:app:transformClassesWithDexForDebug Failed

FAILURE: Build Failed with an exception.

* What went wrong:
Execution Failed for task ':app:transformClassesWithDexForDebug'.
> com.android.build.api.transform.TransformException: com.android.ide.common.process.ProcessException: java.util.concurrent.ExecutionException: java.lang.Unsu
pportedOperationException

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.

BUILD Failed

通过打印的异常信息,可以确定问题是在于 OkHttp 的依赖冲突。@H_403_5@

2. 依赖冲突问题的探究

2.1 使用 Gradle 工具对依赖冲突进行探究

Gradle 相关简介:@H_403_5@

「一」Gradle位置:@H_403_5@

  1. C:Users< 用户名 >.gradlewrapperdistsgradle- < 版本号 > -all<一串识别码>gradle- < 版本号 >
  2. < Android Studio 目录 > gradlegradle- < 版本号 >

「二」Gradle 环境变量配置:@H_403_5@

  1. 在环境变量里添加用户变量: GRADLE_HOME
  2. 在环境变量 path 中增加: %GRADLE_HOME%bin;

此时,我直接使用 Gradle 工具检查此项目的依赖,进入项目目录,执行如下指令进行依赖检查:@H_403_5@

cd app
gradle dependencies

打印出如下图所示的依赖树,依赖树显示了你 build 脚本声明的顶级依赖和它们的传递依赖:@H_403_5@

@H_403_5@

箭头所指的地方为与 OkHttp 相关的库,从依赖树可知,我自行引入的 OkHttp 库替换掉了 Fresco 中的低版本库,但仍旧提示依赖冲突。@H_403_5@

经过多次尝试,发现只有同时去掉这两个对 OkHttp 的依赖时,问题得到解决,build.gradle 文件修改如下:@H_403_5@

dependencies {
    compile 'com.android.support:appcompat-v7:24.0.0'
    compile 'cn.bmob.android:bmob-sdk:3.5.2'
    //compile 'com.squareup.okhttp3:okhttp:3.4.2'
    compile('com.facebook.fresco:imagepipeline-okhttp3:0.12.0',{
        exclude module: "okhttp"
    })
    compile 'com.facebook.fresco:fresco:0.12.0'
}

2.2 对解决依赖冲突问题的尝试

这个问题很奇葩,去掉对 OkHttp 的依赖怎么可以呢?对着错误代码查遍了 Google 和 Stack Overflow,提到的解决方法有如下两条:@H_403_5@

2.2.1 使用 Multidex support library 开启 Multidex 功能

步骤 1:更改 build.grade@H_403_5@

defaultConfig {
    ...
    // Enabling multidex support.
    multiDexEnabled true
}

dependencies {
    ...
    compile 'com.android.support:multidex:1.0.1'
}

步骤 2:设置 Application 类@H_403_5@

public class MyApplication extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        MultiDex.install(this);
    }
}

步骤 3:更改 grade.properties@H_403_5@

org.gradle.jvmargs=-XX:MaxHeapSize\=2048m -Xmx2048m

2.2.2 通过增大可用内存解决「:app:transformClassesForDexForDebug」异常

在 gradle.build 中指定 javaMaxHeapSize:@H_403_5@

android {
    .
    .
    .
    dexOptions {
        javaMaxHeapSize "4g" //specify the heap size for the dex process
    }
}

不过,这两种办法都无益于解决问题。@H_403_5@

3. 追根溯源解决依赖冲突

3.1 问题的精确定位

通过中文搜索引擎搜索之后,在一篇文章中获得了灵感:@H_403_5@

对于如下异常:@H_403_5@

2.Execution Failed for task ':app:transformClassesWithJarMergingForDebug'.

com.android.build.api.transform.TransformException: 
java.util.zip.ZipException: duplicate
entry: android/support/v4/app/BackStackState$1.class

原因:在所添加的 jar 包或 aar 包中也引用了 support-V4,与工程中引用的相冲突 @H_403_5@

Ctrl+N –> 在搜索框中输入 BackStackState –> 查找到所有引用该类的类,这些类即为引起冲突的类 @H_403_5@

去掉本工程中 gradle 中用于引用有冲突的包的代码或者将冲突的代码从 jar 包或 aar 包中移除,确保一个 module 中只引用了一份相同的第三方包@H_403_5@

根据这份解决思路,进行问题的最终解决。@H_403_5@

首先获取如下异常的关键信息:@H_403_5@

Error:Error converting bytecode to dex:
Cause: com.android.dex.DexException: Multiple dex files define Lokhttp3/Address;

由异常信息可知,OkHttp 下的 Address 类有冲突,执行如下步骤:@H_403_5@

  • Ctrl + N
  • 搜索框中输入 Address
  • 查找到所有引用该类的类

搜索到的内容,如下图所示。可知,Bmob 和 OkHttp 中均有该类。@H_403_5@

@H_403_5@

3.2 删掉冲突的 Jar 包

将项目的显示树由 Android 切换到 Project,查看 Bmob 的 Jar 包的结构,发现其中依赖了一个 OkHttp 的 Jar 包。@H_403_5@

@H_403_5@

由于使用了 Gradle 的远程依赖形式,故直接删除冲突的内容无效,须转为使用本地依赖的形式。@H_403_5@

根据 Bmob 官方文档的指示,删除 Bmob 的 Maven 仓库依赖,使用本地 Jar 包形式的依赖,去除对 OkHttp 的 Jar 包的引用,即可顺利解决问题。当然也可以只使用 Bmob 的远程依赖而在 build.gradle 中去掉其他相关「如 OkHttp,Gson,RxJava 等」的依赖。@H_403_5@

4. 参考资料

问题预备@H_403_5@

  1. Android OkHttp 完全解析 是时候来了解 OkHttp 了
  2. Gradle 实战「1」 - 配置环境变量
  3. Gradle 系列教程之依赖管理

MultiDex@H_403_5@

  1. Android分包 MultiDex 原理详解
  2. How to enable multidexing with the new Android Multidex support library

问题解决@H_403_5@

  1. Android Studio 编译中的一些问题解决办法
  2. Android Studio 中如何解决重复依赖导致的 app:transformClassesWithJarMergingForDebug
  3. Bmob的开发文档

相关文章

适配器模式将一个类的接口转换成客户期望的另一个接口,使得原本接口不兼容的类可以相互合作。
策略模式定义了一系列算法族,并封装在类中,它们之间可以互相替换,此模式让算法的变化独立于使用算法...
设计模式讲的是如何编写可扩展、可维护、可读的高质量代码,它是针对软件开发中经常遇到的一些设计问题...
模板方法模式在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中,使得子类可以在不改变算法结...
迭代器模式提供了一种方法,用于遍历集合对象中的元素,而又不暴露其内部的细节。
外观模式又叫门面模式,它提供了一个统一的(高层)接口,用来访问子系统中的一群接口,使得子系统更容...