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) {
    def reset = "\033[0m"      // 重置所有样式
    def bold = "\033[1m"       // 加粗
    def red = "\033[31m"       // 红色,用于错误
    def green = "\033[32m"     // 绿色,用于成功
    def yellow = "\033[33m"    // 黄色,用于告警

    tasks.register("flatDeps${variant.name.capitalize()}", DefaultTask) { task ->
        task.group = "dependency"
        task.description = "flat all dependencies"
        task.doLast {
            def logDir = file("$buildDir${File.separator}outputs${File.separator}logs")
            if (!logDir.exists()) logDir.mkdirs()

            def outFile = file("${logDir}${File.separator}flatDeps${variant.name.capitalize()}.txt")
            if (outFile.exists()) outFile.delete()

            outFile.withOutputStream { outputStream ->
                Configuration configuration = project.configurations.findByName("${variant.name}CompileClasspath")
                if (configuration == null) {
                    configuration = project.configurations.findByName("${variant.name}Compile")
                }
                if (configuration == null) {
                    throw new GradleException("${red}No configuration found for $bold:${project.name}:${variant.name}$reset")
                }
                configuration.resolvedConfiguration.lenientConfiguration.allModuleDependencies
                        .sort { l, r ->
                            l.module.id.group <=> r.module.id.group ?:
                                    l.module.id.name <=> r.module.id.name ?:
                                            l.module.id.version <=> r.module.id.version
                        }
                        .each {
                            def mid = it.module.id
                            outputStream.write("${mid.group}:${mid.name}:${mid.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)