關於 OkHttp 依賴衝突問題的解決過程

雪中亮發表於2018-01-17

「部落格搬家」 原地址: 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位置:

  1. C:\Users< 使用者名稱 >.gradle\wrapper\dists\gradle- < 版本號 > -all<一串識別碼>\gradle- < 版本號 >

  2. < Android Studio 目錄 > \gradle\gradle- < 版本號 >

「二」Gradle 環境變數配置:

  1. 在環境變數裡新增使用者變數: GRADLE_HOME

  2. 在環境變數 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 中均有該類。

Address 類的搜尋結果

3.2 刪掉衝突的 Jar 包

將專案的顯示樹由 Android 切換到 Project,檢視 Bmob 的 Jar 包的結構,發現其中依賴了一個 OkHttp 的 Jar 包。

依賴的 Jar 包查詢

由於使用了 Gradle 的遠端依賴形式,故直接刪除衝突的內容無效,須轉為使用本地依賴的形式。

根據 Bmob 官方文件的指示,刪除 Bmob 的 Maven 倉庫依賴,使用本地 Jar 包形式的依賴,去除對 OkHttp 的 Jar 包的引用,即可順利解決問題。當然也可以只使用 Bmob 的遠端依賴而在 build.gradle 中去掉其他相關「如 OkHttp,Gson,RxJava 等」的依賴。

4. 參考資料

問題預備

  1. Android OkHttp 完全解析 是時候來了解 OkHttp 了
  2. Gradle 實戰「1」 - 配置環境變數
  3. Gradle 系列教程之依賴管理

MultiDex

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

問題解決

  1. Android Studio 編譯中的一些問題解決辦法
  2. Android Studio 中如何解決重複依賴導致的 app:transformClassesWithJarMergingForDebug
  3. Bmob的開發文件

相關文章