gradle dependency

Posted on By ᵇᵒ

前言

工程组件化带来比较显著的依赖冲突,如何快速高效地解决冲突显得尤为重要。

一、树状 dependencies

以树状结构列出 module(这里是app module) 所有的依赖:

gradle :app:dependencies

二、平铺 dependencies

gradle 自身提供的 dependencies 命令提供的树状结构在某些场合下并不是简洁明了,很多时候我们只想单纯知道整个应用使用了哪些依赖,把树状结构平铺并去重后就会方便很多。如下是我自定义的一个 flatDeps task:

project.afterEvaluate {
    project.plugins.withId('com.android.application') {
        project.android.applicationVariants.all { variant ->
            predicate(variant)
        }
    }
    project.plugins.withId('com.android.library') {
        project.android.libraryVariants.all { variant ->
            predicate(variant)
        }
    }
}

def predicate(variant) {
    tasks.create(
            group: "dependency",
            name: "flatDeps${variant.name.capitalize()}",
            description: "flat all dependencies"
    ) {
        doLast {
            def logDir = file("$buildDir${File.separator}outputs${File.separator}logs")
                    .with(true) {
                        it.mkdirs()
                    }

            file("${logDir}${File.separator}flatDeps${variant.name.capitalize()}.txt")
                    .with(true) {
                        delete(it)
                    }
                    .withOutputStream { outputStream ->
                        Configuration configuration
                        try {
                            configuration = project.configurations."${variant.name}CompileClasspath"
                        } catch (Exception ignored) {
                            configuration = project.configurations."_${variant.name}Compile"
                        }
                        configuration.resolvedConfiguration.lenientConfiguration.allModuleDependencies
                                .sort(true, new Comparator<ResolvedDependency>() {
                                    @Override
                                    int compare(ResolvedDependency l, ResolvedDependency r) {
                                        def idL = l.module.id
                                        def idR = r.module.id
                                        def groupResult = idL.group <=> idR.group
                                        def artifactResult = idL.name <=> idR.name
                                        def versionResult = idL.version <=> idR.version
                                        return groupResult != 0 ? groupResult : (artifactResult != 0 ? artifactResult : versionResult)
                                    }
                                })
                                .each {
                                    def identifier = it.module.id
                                    outputStream.write("${identifier.group}:${identifier.name}:${identifier.version}\n".getBytes())
                                }
                    }
        }
    }
}

新建 flatDeps.gradle 脚本,写入上面的自定义 task,然后在相应的 module apply 该脚本,sync 之后即可执行相应 flavor 的 task:flatDepsRelese/flatDepsDebug。输出日志在 ${相应module}/build/outputs/logs/flatDeps.txt,输出的依赖按字母升序。

三、configuration

Gradle 理解:configuration、dependency

四、dependencyInsight

反向查看一个 lib 被哪些 module 依赖:

gradle :app:dependencyInsight --configuration debugCompileClasspath --dependency com.jingdong.wireless.cdyjy:utils

如果配置有 flavor,则需要加上 flavor 名字(参考 Why did gradlew :app:dependencyInsight fail):

gradle :app:dependencyInsight --configuration ${flavor}DebugCompileClasspath --dependency com.jingdong.wireless.cdyjy:utils
  • app 替换成需要查看的 module name
  • debugCompileClasspath 替换成对应的 configuration。 如何查看所有的 configuration:gradle projects --info,找到对应 module 的 Configure project section。
  • com.jingdong.wireless.cdyjy:utils 替换成需要查看的 library(group:artifact)