Android編譯時衝突報錯的完美解決方案

最近在項目的整合和接入第三方sdk的過程中多次遇到DexArchiveMergerException/ transformDexArchiveWithExternalLibsDexMergerForDevelop等報錯,詳細的報錯信息如下,一般有如下兩種場景,一種是依賴衝突,一種是jar衝突。

場景1:

Caused by: com.android.builder.dexing.DexArchiveMergerException: Error while merging dex archives:
...\app\build\intermediates\transforms\dexBuilder\develop\debug\0.jar,   ...\app\build\intermediates\transforms\dexBuilder\develop\debug\1.jar, ...\app\build\intermediates\transforms\dexBuilder\develop\debug\2.jar,   ...\app\build\intermediates\transforms\dexBuilder\develop\debug\3.jar, ...\app\build\intermediates\transforms\dexBuilder\develop\debug\4.jar,   ...\app\build\intermediates\transforms\dexBuilder\develop\debug\5.jar, ...\app\build\intermediates\transforms\dexBuilder\develop\debug\6.jar,   ...\app\build\intermediates\transforms\dexBuilder\develop\debug\7.jar, ...\app\build\intermediates\transforms\dexBuilder\develop\debug\8.jar,   ...\app\build\intermediates\transforms\dexBuilder\develop\debug\9.jar, ...\app\build\intermediates\transforms\dexBuilder\develop\debug\10.jar,   ...\app\build\intermediates\transforms\dexBuilder\develop\debug\11.jar, ...\app\build\intermediates\transforms\dexBuilder\develop\debug\12.jar,   ...\app\build\intermediates\transforms\dexBuilder\develop\debug\13.jar, ...\app\build\intermediates\transforms\dexBuilder\develop\debug\14.jar,   ...\app\build\intermediates\transforms\dexBuilder\develop\debug\15.jar, ...\app\build\intermediates\transforms\dexBuilder\develop\debug\16.jar,   ...\app\build\intermediates\transforms\dexBuilder\develop\debug\17.jar, ...\app\build\intermediates\transforms\dexBuilder\develop\debug\18.jar,   ...\app\build\intermediates\transforms\dexBuilder\develop\debug\19.jar, ...\app\build\intermediates\transforms\dexBuilder\develop\debug\20.jar,   ...\app\build\intermediates\transforms\dexBuilder\develop\debug\21.jar, ...\app\build\intermediates\transforms\dexBuilder\develop\debug\22.jar,   ...\app\build\intermediates\transforms\dexBuilder\develop\debug\23.jar, ...\app\build\intermediates\transforms\dexBuilder\develop\debug\24.jar,   ...\app\build\intermediates\transforms\dexBuilder\develop\debug\25.jar, ...\app\build\intermediates\transforms\dexBuilder\develop\debug\26.jar,   ...\app\build\intermediates\transforms\dexBuilder\develop\debug\27.jar  
at com.android.builder.dexing.D8DexArchiveMerger.getExceptionToRethrow(D8DexArchiveMerger.java:124)
at com.android.builder.dexing.D8DexArchiveMerger.mergeDexArchives(D8DexArchiveMerger.java: 109)
at com.android.build.gradle.internal.transforms.DexMergerTransformCallable.call(DexMergerTransformCallable.java: 101)
at com.android.build.gradle.internal.transforms.ExternalLibsMergerTransform.transform(ExternalLibsMergerTransform.kt: 123)
at com.android.build.gradle.internal.pipeline.TransformTask$2.call(TransformTask.java: 221)
at com.android.build.gradle.internal.pipeline.TransformTask$2.call(TransformTask.java:217)
at com.android.builder.profile.ThreadRecorder.record(ThreadRecorder.java: 102)
... 122 more
Caused by: com.android.tools.r8.CompilationFailedException: Compilation failed to complete
at com.android.tools.r8.utils.ExceptionUtils.withCompilationHandler(ExceptionUtils.java:76)
at com.android.tools.r8.utils.ExceptionUtils.withD8CompilationHandler(ExceptionUtils.java: 45)
at com.android.tools.r8.D8.run(D8.java: 67)
at com.android.builder.dexing.D8DexArchiveMerger.mergeDexArchives(D8DexArchiveMerger.java: 107)
... 127 more
Caused by: com.android.tools.r8.utils.AbortException
at com.android.tools.r8.utils.Reporter.failIfPendingErrors(Reporter.java: 77)
at com.android.tools.r8.utils.Reporter.fatalError(Reporter.java: 58)
at com.android.tools.r8.utils.ExceptionUtils.withCompilationHandler(ExceptionUtils.java: 67)
... 130 more

場景2:

Caused by: java.lang.RuntimeException: com.android.builder.dexing.DexArchiveMergerException: Error while merging dex archives:
C: android\app\build\intermediates\transforms\dexBuilder\develop\debug\0.jar,
C: android\app\build\intermediates\transforms\dexBuilder\develop\debug\1.jar,
C: android\app\build\intermediates\transforms\dexBuilder\develop\debug\2.jar,
C: android\app\build\intermediates\transforms\dexBuilder\develop\debug\3.jar,
C: android\app\build\intermediates\transforms\dexBuilder\develop\debug\4.jar,
C: android\app\build\intermediates\transforms\dexBuilder\develop\debug\5.jar,
C: android\app\build\intermediates\transforms\dexBuilder\develop\debug\6.jar,
C: android\app\build\intermediates\transforms\dexBuilder\develop\debug\7.jar,
C: android\app\build\intermediates\transforms\dexBuilder\develop\debug\8.jar,
C: android\app\build\intermediates\transforms\dexBuilder\develop\debug\9.jar,
C: android\app\build\intermediates\transforms\dexBuilder\develop\debug\10.jar,
C: android\app\build\intermediates\transforms\dexBuilder\develop\debug\11.jar,
C: android\app\build\intermediates\transforms\dexBuilder\develop\debug\12.jar,

1.對於這種因爲衝突導致的問題,一般的解決辦法是找到衝突的根源,也就是在androidstudio的Terminal中輸入如下命令查看依賴數找到衝突的依賴來解決。

gradlew -q app:dependencies

2.然而對於一個大型項目而言,如上方式並不一定可以輕而易舉的找到衝突。因此我們可以嘗試在app的build.gradle中進行如下配置。

android{
  ...
}

configurations.all {
  resolutionStrategy {
    force 'com.squareup.okhttp3:okhttp:3.11.0'
    force 'com.squareup.okio:okio:1.14.0'
    force 'com.android.support.constraint:constraint-layout:1.1.1'
    force 'com.google.code.gson:gson:2.8.5'
    force 'com.android.support:appcompat-v7:27.1.1'
    ...
   }
}
configurations.all {
  resolutionStrategy {
    failOnVersionConflict()
  }
}

dependencies {
   ...
}

相信resolutionStrategy大部分人都用過,專門爲gradle設置編譯的策略,ResolutionStrategy接口中提供了一系列策略方法,我們可以查看源碼根據需要選擇配置。對於一些衝突的場景,特別是集成了一些第三方的sdk後導致項目因爲衝突報錯無法編譯的場景。我們可以選擇直接設置failOnVersionConflict(),目的是在編譯時假如有衝突發生,則直接編譯失敗在控制檯打印報錯信息,具體的可以查看我項目中的報錯。

Could not resolve all dependencies for configuration ':app:productDebugRuntimeClasspath'.
A conflict was found between the following modules:
 - com.squareup.okhttp3:okhttp:3.9.1
 - com.squareup.okhttp3:okhttp:3.2.0
 - com.squareup.okhttp3:okhttp:3.8.0
 - com.squareup.okhttp3:okhttp:3.8.1
這樣一下子就知道項目中有哪些依賴衝突了,然後將衝突的依賴選擇號版本添加到如下的配置中強制指定即可。
configurations.all {
  resolutionStrategy {
    force 'com.squareup.okhttp3:okhttp:3.11.0'
    ...
   }
}

可以有些人會有疑問,我項目多個module中多次引入同一個依賴也沒有衝突啊,其實gradle在編譯時將所有的依賴都引入了,只不過在我們代碼中引用時,gradle默認使用的時最高版本的依賴而已。通過上面的方式可以解決幾乎百分之九十的衝突。另外你還會發現這麼設置後整個app的大小還會減少不少,因爲我們強制指定後,gradle不在將重複的依賴全部引入最終打包到dex中,所以app的體積當然就減少了。

3.通過以上兩種方式幾乎可以解決百分之九十的衝突,但是還有一種場景的衝突還是無法解決。假如我們項目引入了一個第三方的sdk,他裏面引入了一個高德地圖及定位功能,我們項目中也引入了高德地圖的獵鷹軌跡功能,而獵鷹軌跡功能只能以jar包的形式引用(獵鷹jar包中也引了高德定位功能),這樣我們編譯項目時,必然會導致衝突,而且這種衝突是無法通過配置gradle來解決的。那該如何是好呢?這個時候就該拿出大殺器了。

對於這種場景我們可以使用jarjar.jar,將第三方比如說高德獵鷹jar等包名進行替換,這樣在項目編譯打包生成dex文件時就不會因爲同名文件導致衝突。

以上就是解決依賴衝突的所有辦法,一般的衝突都可以配置gradle進行解決,對於一些疑難雜症只能使用偏方了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章