解決aar內含jar包衝突的方法

1 背景和問題

最近在嘗試將兩個SDK集成到一個App中。這兩個SDK都是以aar格式提供的,在分別集成時均可以正常工做。但若是同時使用兩個SDK,編譯器會報告錯誤:java

Execution failed for task ':transformClassesWithJarMergingForDebug'.
> com.android.build.api.transform.TransformException: java.util.zip.ZipException: duplicate entry: com/somewhere/over/the/Rainbow.class

原來這兩個SDK都使用了同一個jar包,並將其打包在aar中。android

2 解決

使用gradle和com.android.application插件編譯Android工程時,gradle會將工程所依賴的aar包解壓縮到目錄api

build\intermediates\exploded-aar

每一個aar包獨佔一個子目錄。一般發生衝突的文件會保存在libs、jars、jni等幾個子目錄下。找到並刪除衝突文件,就能夠解決編譯問題。app

gradle可能會從新對aar進行解壓縮,所以手動刪除是不行的。觀察編譯的錯誤消息,編譯錯誤發生在任務transformClassesWithJarMergingForDebug中。只要爲它增長一個處理衝突的前置任務就好了。工具

task clearDuplicatedClasses {
    doFirst {
        def buildDir = project.getBuildDir()
        def files = ["\\intermediates\\exploded-aar\\MyAar\\jars\\libs\\Abc.jar",
                     "\\intermediates\\exploded-aar\\MyAar\\jars\\libs\\Def.jar",
                     "\\intermediates\\exploded-aar\\MyAar\\jars\\libs\\Xyz.jar"]

        files.each {
            delete new File(buildDir, it)
        }
    }
}

project.afterEvaluate {
    project.tasks.findByName("transformClassesWithJarMergingForDebug").dependsOn(clearDuplicatedClasses)
}

transformClassesWithJarMergingForDebug是動態添加到project.tasks中的,若是直接寫成gradle

project.tasks.transformClassesWithJarMergingForDebug.dependsOn(clearDuplicatedClasses)

gradle會報告找不到任務。ui

3 思考和附錄

若是咱們須要在已有的jar包(或SDK)上作一些封裝,並將封裝後的代碼做爲SDK提供給客戶。這時咱們能夠考慮構建兩個版本,一個只包含封裝層代碼,另外一個包含所有代碼。以避免出現jar包衝突的狀況,方便客戶使用。lua

若是想了解一個gradle任務依賴於哪些任務,可使用-dry-run(或-m)參數執行這個任務:spa

.\gradlew.bat -m assembleDebug

Android gradle plugin插件位於$home\.gradle\caches\modules-2\files-2.1\com.android.tools.build\gradle-core的子目錄下,名字是gradle-core-X.Y.Z.jar。這個jar包沒有混淆,可使用反編譯工具查看裏面的代碼。編譯Android工程使用的不少任務都定義在裏面。插件

使用gradle編譯時,不少任務是動態添加的。要了解有project包含了哪些任務,以及這些任務對應的類,能夠在build.gradle裏增長一個任務

task listAllTasks {
    doFirst {
        println("========================================")
        getProject().getTasks().forEach { task ->
            print(task.getName())
            print("\t")
            println(task.getClass().getName())
        }
        println("========================================")
    }
}

若是要查看某個特定任務對應的類,能夠用

task printTaskClass {
    doFirst {
        println("========================================")
        println(getProject().getTasks().findByName("prepareDebugDependencies").getClass())
        println("========================================")
    }
}

4 編輯記錄

2019年07月30日 創建文檔。

相關文章
相關標籤/搜索