1. 程式人生 > >Error while generating the main dex list

Error while generating the main dex list

今天編譯專案,編譯報錯。

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':app:transformClassesWithMultidexlistForInstant_runDebug'.
> com.android.build.api.transform.TransformException: Error while generating the main dex list.

習慣上直接 copy 錯誤 ,在 stackoverflow 上查詢答案。
花了十幾分鍾仍然沒找到答案。
直接在 Android Studio 中的命令列中執行。

gradle  assembleDebug  --stacktrace

發現了以下錯誤 :

Caused by: com.android.tools.r8.errors.CompilationError: Program type already present: okhttp3.Authenticator$1

原因很簡單 jar 包衝突了 。
我使用了一個第三方庫,第三方庫依賴了 OkHttp 。 而我專案中原本就有 OkHttp 。

 compile ("com.facebook.react:react-native:0.55.4")

找到問題的原因後,解決就很快了。直接移除第三方庫所依賴的 OkHttp 即可。

    compile ("com.facebook.react:react-native:0.55.4") {
        exclude group: 'com.squareup.okhttp3'
    }

如果你也遇到了這樣的報錯 , 可能是 jar 包衝突 。
通常這樣的問題是在 Gradle 中新新增的依賴第三方庫引起的。

如何來排查複雜些的問題呢 ?

Android 專案中大部分通過 Gradle 遠端依賴, 建議通過檢視依賴樹來排查問題 :
例如我的 Android 工程主 Module 名稱為 app 。我想檢視依賴樹,進入專案根目錄,執行命令:

gradlew
app:dependencies

Terminal 中會打印出很多文字 , 如 :

這裡寫圖片描述

其中 recyclerview 是我在 build.gradle 中直接依賴的。

implementation 'com.android.support:recyclerview-v7:26.1.0

而下面三行程式碼是 recyclerview 所依賴的庫。

|    +--- com.android.support:support-annotations:26.1.0 (*)
|    +--- com.android.support:support-compat:26.1.0 (*)
|    \--- com.android.support:support-core-ui:26.1.0 (*)

因此大多數情況下的衝突是因為,依賴庫所依賴的其他庫版本衝突。

想要處理這種問題,我給大家介紹幾種方法。

exclude

exclude : 剔除依賴 。還給大家舉上面的例子。
recyclerview 不想要依賴 com.android.support:support-annotations:26.1.0 怎麼辦 ?
有辦法 :

    implementation ('com.android.support:recyclerview-v7:26.1.0'){
        exclude group: 'com.android.support', module: 'support-annotations'  // 根據組織名 + 構建名剔除
        // 你也可以分別通過  group 和 module 剔除 對應的模組。
    }

執行後的依賴樹如下 :

+--- com.android.support:recyclerview-v7:26.1.0
|    +--- com.android.support:support-compat:26.1.0 (*)
|    \--- com.android.support:support-core-ui:26.1.0 (*)

force

force : 強制指定依賴版本。
例如,我想要所有 com.android.support:support-annotations:26.1.0 的依賴版本為 27.1.1 怎麼辦呢 ?
在只需要在 build.gradle 中加上 force true 即可 :

   implementation("com.android.support:support-annotations:27.1.1"){
        force true
    }

執行後檢視依賴樹的結果 :

+--- com.android.support:recyclerview-v7:26.1.0
|    +--- com.android.support:support-annotations:26.1.0 -> 27.1.1
|    +--- com.android.support:support-compat:26.1.0 (*)
|    \--- com.android.support:support-core-ui:26.1.0 (*)

大家看到多了 -> 27.1.1 . 也就是原依賴版本為 26.1.0 ,在工程中修改依賴為 27.1.1 。

transitive

transitive : 依賴傳遞特性,使用的時候,通常設定為 false 。即關閉依賴傳遞

例如專案中不希望 recyclerview 使用它所依賴的庫 :

|    +--- com.android.support:support-annotations:26.1.0 (*)
|    +--- com.android.support:support-compat:26.1.0 (*)
|    \--- com.android.support:support-core-ui:26.1.0 (*)

在只需要在 build.gradle 中加上 transitive false 即可 :

 implementation ('com.android.support:recyclerview-v7:26.1.0'){
        transitive  false
 }

執行後檢視依賴樹的結果 , recyclerview 的依賴都消失了。當然這是一個危險的操作,因為
缺少依賴,你可能無法正常編譯。最好確認你專案中已經依賴了你所剔除在外的庫。

+--- com.android.support:recyclerview-v7:26.1.0

上述操作等同於 :

 implementation('com.android.support:recyclerview-v7:26.1.0') {
        exclude group : 'com.android.support'
  }

因為 recyclerview 依賴的三個庫組織名都是 com.android.support

總結

解決衝突用的最多是 force 和 exclude 。
本來這麼簡單一個問題,應該在1分鐘內解決的。卻前前後後花了 十幾分鍾。
發現自己太依賴 Google 了。
首先應該是鍛鍊自己排查問題的能力,然後再面向 Github 程式設計 和 面向 stackoverflow 程式設計。