「部落格搬家」 原地址: 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
問題解決