EasyDependency:简单优雅管理组件化的依赖配置

3,489 阅读6分钟

在实际的开发中,随着项目的复杂度的提升,为了维护代码的复用率和可读性,项目的组件化是一种比较受欢迎的解决方案。

在这个过程中,一个小的问题是关于组件化工程的依赖管理。随着工程中的模块越来越多,整个工程的编译时间会增多(虽然Android studio在这方面的改进已经越来越好)。为了缩短编译的时长,一种简单的解决方案是:

  • 通过aar/jar远程构件依赖模块

这种方案的好处是,项目依赖的是已经编译完成的代码,每次编译工程的时候,这些构件不需要参与编译的过程,可以直接缩短时间。但是使用这种解决方案之后又会存在以下两个问题:

  • 开发阶段,aar/jar包不稳定,需要频繁的修改和发版
  • aar/jar远程构件依赖不方便调试(比如无法快速插入调试代码、调试日志)

EasyDependency 就是一个为了解决以上的问题而诞生的轻量级的简洁解决方案。

关于EasyDependency

EasyDependency 是一个基于groovy实现的gradle插件,可以直接在已有的Android studio的项目中快速接入使用。目前,EasyDependency主要提供以下两个功能:

发布构件

目前关于发布aar/jar构件到maven的仓库插件、脚本和教程多而杂乱,EasyDependency内部集成了简单使用的上传构件的功能,只需要提供必要的参数即可实现功能。具体可以参考下面的使用方案。

动态更换依赖配置

正如前面所提及的,当我们使用aar依赖提高编译速度的同时,我们面临了另外的两个问题。EasyDependency内部对这个问题提供了自己的解决方案,即通过简单的配置动态的更改项目实际所使用的模块依赖。

比如在项目中存在A、B两个模块,其中模块A依赖模块B。在模块A的build.gradle文件中配置如下:

dependencies {
    implementation project(':B') // 通过源码依赖B模块
    //implementation groupIdB:artifactIdB:versionB // 通过远程构件依赖B模块
}

在上面的配置中就是我们常规的解决方案,当需要更换依赖的时候,我们把其中的依赖方式注释掉,只保留所需要的依赖方案。

如果项目中只有一两个的模块,并且彼此的依赖关系比较简单的时候,这样的方式简单可用,但是,但项目中的模块数多大十个左右的时候,再使用这样的方式就会捉襟见肘了。

EasyDependency就是为了简单清晰集中的管理这种动态依赖配置问题的。EasyDependency内部实现原理如下:

  1. 在当前模块中添加动态依赖的配置块dynamicDependency(配置方法参考下文)
  2. 查询当前模块中所有的本地源码依赖
  3. 比较本地依赖与配置块,当对应的本地依赖所属的配置块的debuggable属性是false的时候,表示需要使用远程构件依赖替换本地源码依赖。此时根据其他的配置参数确定远程构件的地址进行依赖替换。关于依赖替换的实现,使用的是gradle当中的dependencySubstitution的api判断

具体的使用方案,参考下面的使用方案。

EasyDependency快速接入使用

目前,EasyDependency已经发布到bintray上,你可以快速的接入使用。

  1. 在根项目的build.gradle文件中添加依赖及插件使用的配置

    // 引入插件,注意这个插件只能在根项目的gradle文件中引入
    // 内部会完成根项目下的各个子模块的配置
    apply plugin: 'easy-dependency'
    
    buildscript {
        repositories {
            ...
            // 添加仓库地址
            jcenter()
        }
        dependencies {
            ...
            //添加依赖
            classpath 'tech.easily:EasyDependencyPlugin:1.0.1'
            // NOTE: Do not place your application dependencies here; they belong
            // in the individual module build.gradle files
        }
    }
    
  2. 配置发布构件到maven仓库

    在各个需要发布构件到module的build.gradle文件中添加以下配置

    mavenPublish{
        version='0.0.1-SNAPSHOT' // 如果不包含SNAPSHOT,则发布到release的仓库
        groupId='your group id'
        artifactId='your artifact id' // 如果不配置,则使用模块的名称作为其默认值
        userName="your maven repo user's name"
        password="your maven repo password"
        releaseRepo="your release maven repo address"
        snapshotRepo="your snapshot maven repo address"
    }
    

    如果项目需要配置的模块很多的时候,我们可以直接通过下面的方式直接在根项目的build.gradle文件中配置

    subprojects {
    	// EasyDependency不会在这个模块中添加发布构件的功能,所以这里添加配置参数的时候需要排除
        if (project.name == "app") {
            return
        }
        mavenPublish {
            // 这里直接使用模块名称作为artifactId
            version='0.0.1-SNAPSHOT' 
            groupId = maven.config.groupId
            releaseRepo = maven.config.releaseRepo
            snapshotRepo = maven.config.snapshotRepo
        }
    }
    

    如果每个模块的发布版本号并不一致的情况下,我们可以把上面的version配置移除,同时在各个模块的build.gradle文件中分别添加以下的配置即可

    mavenPublish.version="0.0.3-SNAPSHOT"
    

    这样能够更加统一的管理,复用配置

  3. 配置动态替换依赖

    在各个需要进行动态依赖替换的module的build.gradle文件中添加以下配置

    //需要把本地源码的依赖配置上
    //这样子哪怕插件移除了,代码也能正常工作
    dependencies {
        implementation project(':B')
    }
    
    dynamicDependency{
        //这个key对应的是本地模块的名称(注意这个本地模块应该在依赖当中有配置,如上所示)
        B{
            debuggable=true //如果是true,则使用本地模块作为依赖参与编译,否则使用下面的配置获取远程的构件作为依赖参与编译
            groupId="target archive's group id"
            artifactId="target archive's archive id" // 默认使用模块的名称作为其值
            version="target archive's version"
        }
        // 如果有更多的模块需要进行动态依赖配置,则继续添加对应的配置快在里面即可
        ...
    }
    

    同样的,如果需要多个模块的依赖实现动态修改的时候,可以参考上面的统一配置的方案。

以上就是关于EasyDependency的实现和使用说明,欢迎关注和star我的GitHub仓库EasyDependency

如果你对应这个方案的实现/使用有什么问题,欢迎提issue。如果你在处理组件化项目的依赖过程中遇到其他需要解决的问题也欢迎提出,我会让它更加完善。

如果对于组件化工程的依赖问题你有其他的解决方案,欢迎一起交流,谢谢!