有關 Android Studio 重複引入包的問題和解決方案
有關 Android Studio 重複引入包的問題和解決方案
隨著產品功能需求的增加,我們開發的安卓專案不得不入引入越來越多的第三方庫。這些三方庫可能以 Jar 包的形式放置在 libs 目錄下,可能以 Gradle 遠端依賴的形式下載引入,也可能是以 Library Module 的形式放置在工程目錄下,等等。
隨之而來的問題是,複雜的依賴關係很可能導致重複引入包的問題。比較常見的使用場景就是 support-v4 包的重複引入。這樣就會導致,執行 Run 操作打包生成 Apk 檔案時出現類似這樣的 DexException 錯誤提示,導致編譯失敗:
1
2
Error:Execution failed for task ‘:app:transformClassesWithDexForDebug’.
com.android.build.api.transform.TransformException: com.android.ide.common.process.ProcessException: java.util.concurrent.ExecutionException: com.android.dex.DexException: Multiple dex files define Landroid/support/v4/app/ActivityCompatHoneycomb;
有多種使用場景會出現這種問題。根據解決方案的不同,大體上可以分為兩種:本地 Jar 包重複嵌入和 Gradle 遠端重複依賴。
第一種,比較好理解。比如 app module 與 library module 各自 libs 目錄中嵌入了相同的 Jar 包。這種情況也比較好解決,只需要將 app module 下的重複 jar 包刪除即可。
第二種,稍微複雜一點。比如對於 Gradle 遠端依賴的兩個第三方庫,他們內部同時依賴相同的另一個輔助第三方庫。這個時候我們就沒辦法像第一種情況那樣手動刪除本地檔案。好在 Gradle 外掛提供了相應的解決方案,即使用 exclude 語法,如:
compile 'com.yifeng.example:example-1:1.0'
compile ('com.yifeng.example:example-2:1.0') {
exclude group: 'com.android.support', module: 'support-v4'
}
如例子中所示,遠端依賴的第三方庫 example-1 與 example-2 內部同時引入 support-v4 包,那麼只需要在其中一個的引入地方新增 exclude 語句,根據 group 和 module 過濾規則,將相同引入的 v4 包剔除在外即可。
當需要在一個依賴中去除多個遞迴依賴項時,可以使用多條 exclude 語句,比如:
compile ('com.wdullaer:materialdatetimepicker:3.2.2') {
exclude group: 'com.android.support', module: 'support-v4'
exclude group: 'com.android.support', module: 'design'
}
還有一種更簡單的寫法,使用 Groove 語言的迴圈語句,模板如下(同樣適用於 module 規則):
compile() { dep ->
[group1, group2].each{ group -> dep.exclude group: group }
}
對於上面的例子,便可以改造成:
compile() { dep ->
['support-v4', 'support-v13', 'design'].each{ module -> dep.exclude module: module }
}
更多細節,參考:ModuleDependency)。
以上兩種場景算是比較好處理的。還有一種特殊情況,就是不同第三方庫內部出現相同包名相同檔名的 java 類。這種情況出現的概率很低,但是不幸的是我在工作中就遇見過。
當時專案中引入的 友盟統計 和 移動統一認證 的 SDK 出現重複引入問題,執行 Run 操作編譯打包時出現 duplicate entry 錯誤,如圖:
通過錯誤提示,很容易就找到錯誤出處,我們看下兩個 SDK 中的 jar 包原始碼:
友盟統計 SDK
移動統一認證 SDK
雖然相同包名相同類名的檔案在不同 SDK 中出現的概率極低,但是一旦出現,處理起來就比較棘手。最好的解決方案就是聯絡提供 SDK 的技術人員反映問題,讓其通過修改原始碼重新打包一個新的 Jar 包。
還有一個解決辦法就是,重新命名 Jar 包裡的包名或者檔名。網上也有一個工具:jarjar.jar,可以幫助我們重新命名包名和檔名,以及 Jar 包中的相關程式碼引用路徑。參考地址如下:
GitHub 原始碼:https://github.com/shevek/jarjar
Jar 檔案下載:https://code.google.com/archive/p/jarjar/downloads
該工具提供有多種使用方式,最簡單實用的就是通過命令列使用。舉個例子,開啟命令列工具,執行:
1
java -jar jarjar-1.4.jar process rule.txt example.jar example_output.jar
其中,rule.txt 是包含重新命名規則的檔案,內容如下:
1
rule p.rn.asm.** com.yifeng.example.@1
我們看一下重新命名前後 Jar 包內容的程式碼對比圖:
可以看到,不僅包名改變,Jar 包中的相關類引用路徑也自動改變。這種 Jar 包重新命名的方式雖然能解決重複引入包的問題,但不是長久之計,需要後續持續關注 SDK 的升級替換。
不同 Jar 包包含相同檔案(路徑也相同)的情況還有一種,就是 duplicate files 錯誤。多個 Jar 包包含重複的檔案。這種情況在網上看到過,出自 StackOverFlow,錯誤提示類似:
Error:duplicate files during packaging of APK E:\Code\iDoc\app\build\outputs\apk\app-debug-unaligned.apk
Path in archive: META-INF/license.txt
Origin 1: E:\Code\iDoc\app\libs\spring-core-3.1.0.RELEASE.jar
Origin 2: E:\Code\iDoc\app\libs\spring-web-3.1.0.RELEASE.jar
You can ignore those files in your build.gradle:
android {
packagingOptions {
exclude 'META-INF/license.txt'
}
}
可以看到,解決方案已經在錯誤提示中有給出,使用 packagingOptions 配置的 exclude 語句刪除重複檔案即可,比如:
packagingOptions {
exclude 'META-INF/DEPENDENCIES'
exclude 'META-INF/NOTICE'
exclude 'META-INF/LICENSE'
exclude 'META-INF/LICENSE.txt'
exclude 'META-INF/NOTICE.txt'
}
最後再補充一點,關於 Gradle 依賴的 Scope 問題。通常依賴某個第三方庫我們使用的都是 compile 關鍵字,實際上,還有一個 Provided 關鍵字偶爾也會用到。
開啟 Project Structure,檢視 Modules 的 Dependencies 內容時,可以看到每一個依賴項的右邊有個 Scope 選項:
compile 表示依賴的第三方庫在工程編譯階段、測試階段和 Apk 執行階段都需要使用到;而 provided 表示該第三方庫僅僅是在編譯階段和測試階段使用到,不會出現在執行階段,即表示不會打包到最終的 apk 檔案中去,目標執行環境已經包含有該第三方庫。(貌似 Dagger2 的使用可能會涉及到這個問題。)
關於 Scope 的詳細介紹,可以參考文章:PROVIDED SCOPE IN GRADLE。
本文轉載自 亦楓 感謝大佬
原文:http://yifeng.studio/2017/05/20/android-studio-duplicate-introduce-jar/
相關文章
- Android studio glide包重複問題AndroidIDE
- 如何解決 Android Studio 上遠端依賴包重複的問題Android
- Debian 11 關閉 swap 遇到的問題和解決方案
- No debuggable processes(Android Studio沒有可除錯應用)問題解決方案Android除錯
- 粘包問題原因和解決方法
- android中The connection to adb is down,問題和解決Android
- Android studio無法提醒v4包的解決方案Android
- Go 之基礎速學 (十四) golang 裡 a 包引入 b 包 b 包引入 a 包問題的解決Golang
- 關於 Go Modules 巢狀引入本地包的問題Go巢狀
- Android Studio3.1.2及Android P相關問題Android
- GT911驅動遇到的問題和解決方案
- Composer 使用過程中遇到的問題和解決方案
- Android平臺HTTPS抓包解決方案及問題分析AndroidHTTP
- android studio jdk問題AndroidJDK
- composer依賴相關的問題和解決辦法
- 關於 Android studio 在xml中不提示的問題AndroidXML
- 關於無法用 https 登入 SAP ABAP Netweaver 系統的問題和解決方案HTTP
- 解決taro小程式中引入axios包過大的問題iOS
- 資料庫檔案複製問題和解決辦法資料庫
- xxl-job濫用netty導致的問題和解決方案Netty
- Android 解析包時出現問題 的解決方案(應用檢查更新)Android
- TCP 粘包 - 拆包問題及解決方案TCP
- 【Android Studio】解決 Android Studio2.2 無法輸入中文標點符號的問題Android符號
- Android studio 問題記錄Android
- Android Studio常見問題(+)Android
- 在Android裝置上使用極光推送id重複的原因分析和解決辦法Android
- 答讀者問:關於隱式 id 重複的問題
- Android Studio 報錯解決方案 一Android
- 解決winform窗體重複建立問題ORM
- Windows作業系統常見故障問題和解決方案Windows作業系統
- 解決alertmanager重複傳送訊息的問題
- 解決生產日誌重複列印的問題
- 解決Linq.ToDictionary()時的鍵重複問題
- Netty解決粘包和拆包問題的四種方案Netty
- Android studio maven配置 gradle下載慢問題解決AndroidMavenGradle
- 解決 HttpServletRequest 的輸入流不能重複讀的問題HTTPServlet
- 關於azkaban上傳job壓縮包報錯問題的解決方案
- 解決Android studio中gradle依賴下載太慢的問題AndroidGradle