「博客搬家」 原地址: CSDN 原发表时间: 2016-11-18
OkHttp 是一个流行的开源网络请求库。许多第三方库的底层都是使用 OkHttp 实现网络请求,所以 OkHttp 相关的依赖冲突问题就变得很难避免,下文是我所遇到的一次关于 OkHttp 的依赖冲突问题,通过对 Gradle 工具及 Android Studio 的灵活使用,解决了此问题。
1. 关于 OkHttp 的依赖冲突
我的项目中, build.gradle 文件中设置的主要依赖:
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 的过程中,出现了较为诡异的情况:
- 使用 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
报错,所报错误分别如下 :
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 的依赖冲突。
2. 依赖冲突问题的探究
2.1 使用 Gradle 工具对依赖冲突进行探究
Gradle 相关简介:
「一」Gradle位置:
C:\Users< 用户名 >.gradle\wrapper\dists\gradle- < 版本号 > -all<一串识别码>\gradle- < 版本号 >
< Android Studio 目录 > \gradle\gradle- < 版本号 >
「二」Gradle 环境变量配置:
在环境变量里添加用户变量: GRADLE_HOME
在环境变量 path 中增加: %GRADLE_HOME%\bin;
此时,我直接使用 Gradle 工具检查此项目的依赖,进入项目目录,执行如下指令进行依赖检查:
cd app
gradle dependencies
打印出如下图所示的依赖树,依赖树显示了你 build 脚本声明的顶级依赖和它们的传递依赖:
箭头所指的地方为与 OkHttp 相关的库,从依赖树可知,我自行引入的 OkHttp 库替换掉了 Fresco 中的低版本库,但仍旧提示依赖冲突。
经过多次尝试,发现只有同时去掉这两个对 OkHttp 的依赖时,问题得到解决,build.gradle 文件修改如下:
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,提到的解决方法有如下两条:
2.2.1 使用 Multidex support library 开启 Multidex 功能
步骤 1:更改 build.grade
defaultConfig {
...
// Enabling multidex support.
multiDexEnabled true
}
dependencies {
...
compile 'com.android.support:multidex:1.0.1'
}
步骤 2:设置 Application 类
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
MultiDex.install(this);
}
}
步骤 3:更改 grade.properties
org.gradle.jvmargs=-XX:MaxHeapSize\=2048m -Xmx2048m
2.2.2 通过增大可用内存解决「:app:transformClassesForDexForDebug」异常
在 gradle.build 中指定 javaMaxHeapSize:
android {
.
.
.
dexOptions {
javaMaxHeapSize "4g" //specify the heap size for the dex process
}
}
不过,这两种办法都无益于解决问题。
3. 追根溯源解决依赖冲突
3.1 问题的精确定位
通过中文搜索引擎搜索之后,在一篇文章中获得了灵感:
对于如下异常:
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 , 与工程中引用的相冲突
Ctrl+N –> 在搜索框中输入 BackStackState –> 查找到所有引用该类的类,这些类即为引起冲突的类
去掉本工程中 gradle 中用于引用有冲突的包的代码或者将冲突的代码从 jar 包或 aar 包中移除,确保一个 module 中只引用了一份相同的第三方包
根据这份解决思路,进行问题的最终解决。
首先获取如下异常的关键信息:
Error:Error converting bytecode to dex:
Cause: com.android.dex.DexException: Multiple dex files define Lokhttp3/Address;
由异常信息可知,OkHttp 下的 Address 类有冲突,执行如下步骤:
Ctrl + N
在搜索框中输入 Address
查找到所有引用该类的类
搜索到的内容,如下图所示。可知,Bmob 和 OkHttp 中均有该类。
3.2 删掉冲突的 Jar 包
将项目的显示树由 Android 切换到 Project,查看 Bmob 的 Jar 包的结构,发现其中依赖了一个 OkHttp 的 Jar 包。
由于使用了 Gradle 的远程依赖形式,故直接删除冲突的内容无效,须转为使用本地依赖的形式。
根据 Bmob 官方文档的指示,删除 Bmob 的 Maven 仓库依赖,使用本地 Jar 包形式的依赖,去除对 OkHttp 的 Jar 包的引用,即可顺利解决问题。当然也可以只使用 Bmob 的远程依赖而在 build.gradle 中去掉其他相关「如 OkHttp,Gson,RxJava 等」的依赖。
4. 参考资料
问题预备
MultiDex
问题解决