解决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日 创建文档。

相关文章
相关标签/搜索