美文网首页
如何理清楚 Android 工程的依赖关系?

如何理清楚 Android 工程的依赖关系?

作者: 沐小晨曦 | 来源:发表于2020-11-30 22:54 被阅读0次

    前言

    在 Medium 上看到一篇文章:How to display your Android project dependency graph in your README file

    讲的是如何在你的 GitHub README 文件里面展示 Android 项目的依赖关系图。

    它其实就是写了一个 Gradle Task 脚本,源文件如下:projectDependencyGraph.gradle

    代码:

    // From https://github.com/JakeWharton/SdkSearch/blob/master/gradle/projectDependencyGraph.gradle
    // The only difference here is the output directory.
    
    task projectDependencyGraph {
      doLast {
        def dot = new File(rootProject.rootDir, 'gradle/dependency-graph/project.dot')
        dot.parentFile.mkdirs()
        dot.delete()
    
        dot << 'digraph {\n'
        dot << "  graph [label=\"${rootProject.name}\\n \",labelloc=t,fontsize=30,ranksep=1.4];\n"
        dot << '  node [style=filled, fillcolor="#bbbbbb"];\n'
        dot << '  rankdir=TB;\n'
    
        def rootProjects = []
        def queue = [rootProject]
        while (!queue.isEmpty()) {
          def project = queue.remove(0)
          rootProjects.add(project)
          queue.addAll(project.childProjects.values())
        }
    
        def projects = new LinkedHashSet<Project>()
        def dependencies = new LinkedHashMap<Tuple2<Project, Project>, List<String>>()
        def multiplatformProjects = []
        def jsProjects = []
        def androidProjects = []
        def javaProjects = []
    
        queue = [rootProject]
        while (!queue.isEmpty()) {
          def project = queue.remove(0)
          queue.addAll(project.childProjects.values())
    
          if (project.plugins.hasPlugin('org.jetbrains.kotlin.multiplatform')) {
            multiplatformProjects.add(project)
          }
          if (project.plugins.hasPlugin('org.jetbrains.kotlin.js')) {
            jsProjects.add(project)
          }
          if (project.plugins.hasPlugin('com.android.library') || project.plugins.hasPlugin('com.android.application')) {
            androidProjects.add(project)
          }
          if (project.plugins.hasPlugin('java-library') || project.plugins.hasPlugin('java')) {
            javaProjects.add(project)
          }
    
          project.configurations.all { config ->
            config.dependencies
                .withType(ProjectDependency)
                .collect { it.dependencyProject }
                .each { dependency ->
                  projects.add(project)
                  projects.add(dependency)
                  rootProjects.remove(dependency)
    
                  def graphKey = new Tuple2<Project, Project>(project, dependency)
                  def traits = dependencies.computeIfAbsent(graphKey) { new ArrayList<String>() }
    
                  if (config.name.toLowerCase().endsWith('implementation')) {
                    traits.add('style=dotted')
                  }
                }
          }
        }
    
        projects = projects.sort { it.path }
    
        dot << '\n  # Projects\n\n'
        for (project in projects) {
          def traits = []
    
          if (rootProjects.contains(project)) {
            traits.add('shape=box')
          }
    
          if (multiplatformProjects.contains(project)) {
            traits.add('fillcolor="#ffd2b3"')
          } else if (jsProjects.contains(project)) {
            traits.add('fillcolor="#ffffba"')
          } else if (androidProjects.contains(project)) {
            traits.add('fillcolor="#baffc9"')
          } else if (javaProjects.contains(project)) {
            traits.add('fillcolor="#ffb3ba"')
          } else {
            traits.add('fillcolor="#eeeeee"')
          }
    
          dot << "  \"${project.path}\" [${traits.join(", ")}];\n"
        }
    
        dot << '\n  {rank = same;'
        for (project in projects) {
          if (rootProjects.contains(project)) {
            dot << " \"${project.path}\";"
          }
        }
        dot << '}\n'
    
        dot << '\n  # Dependencies\n\n'
        dependencies.forEach { key, traits ->
          dot << "  \"${key.first.path}\" -> \"${key.second.path}\""
          if (!traits.isEmpty()) {
            dot << " [${traits.join(", ")}]"
          }
          dot << '\n'
        }
    
        dot << '}\n'
    
        def p = 'dot -Tpng -O project.dot'.execute([], dot.parentFile)
        p.waitFor()
        if (p.exitValue() != 0) {
          throw new RuntimeException(p.errorStream.text)
        }
    
        println("Project module dependency graph created at ${dot.absolutePath}.png")
      }
    }
    

    脚本内容就是用 dot 生成一个 .dot 文件,这个 dot 是啥呢?

    dot 是图形描述语言,简单来说就是用来描述一个图片的,详细见维基百科上的说明:DOT(graph description languang)

    不过该脚本里面涉及到了把 dot 文件转 png 的操作,所以你的机器上需要安装 Graphviz。这玩意就是把 dot 转 png 的工具,为了方便你还需要安装一个 State Art(Android Studio Plugin 里面可以直接搜到),然后你就可以直接运行这个 task 了:

    ./gradlew projectDependencyGraph
    

    然后就会生成一个类似下面的图片:

    project.png

    不过呢,该文章还提到就是用 GitHub 的 Action 自动去生成这个图片,感兴趣的小伙伴可以去康康原文撒~

    总结一下

    其实知道有这个玩意就行,比如 dot ,到需要的时候再去好好看~

    相关文章

      网友评论

          本文标题:如何理清楚 Android 工程的依赖关系?

          本文链接:https://www.haomeiwen.com/subject/xixjwktx.html