在组件化开发的时候,会面临的一个问题就是组件的调试。
即组件和主工程不在同一个工程目录下,主工程对组件的依赖,是通过依赖组件发布的aar包的方式引入。当组件开发了新的功能,就会发布一个新的 aar 包,并在主工程引入。
但如果这种方式带来的问题就是,如果组件有bug或者需要调试的时候,就会带来不便。具体来说就是,如果改一个问题,就发布一个组件的 aar 包,然后在主工程验证问题是否被修复成功。 这样就会频繁的发布 aar 包,而且调试的效率也低,那有没有办法在开发阶段,直接引用 组件module,而不使用组件的 aar 包呢?答案当然是有的,下面就来介绍一下具体的实现方案。
准备工作:
假设主工程路径:/Users/mei/WorkSpace/AndroidProjects/TestModuleDep
组件工程路径:/Users/mei/WorkSpace/AndroidProjects/module-user/user
组件的maven路径:com.mei.module:user:1.0.0
在主工程的 build.gradle 文件中,引入 user 组件:
dependencies {
implementation 'com.mei.module:user:1.0.0'
}
一、组件module(源码)依赖方式
从上面的介绍可以知道,主工程 依赖 user 组件,是通过依赖 user 组件的 aar 包的方式进行的。如果想本地调试的话,可以改成依赖组件module 的方式。具体操作如下:
1、include 组件 module
在主工程的 settings.gradle 文件中,把 组件module 加入编译,即 include 组件module。组件跟主工程不在同一个工程目录下,所以,组件module 的 include 方式也有所不同:
include ":user"
project(":user").projectDir = file("/Users/mei/WorkSpace/AndroidProjects/module-user/user")
如上代码所示,在 主工程的 settings.gradle 文件中,增加上述代码,就可以把 组件module 以 include 的方式,加入到主工程中。
2、依赖组件module
在主工程的 app module 中,依赖组件module,即在 app 的 build.gradle 文件中,依赖组件module,同时,把组件的 aar 包依赖给注释掉:
dependencies {
implementation project(':user')
}
经过上面两步操作,就可以直接依赖组件的源码,而不是组件的 aar 包了,调试起来就非常方便了,不用每次改动都发布一个aar 包。
通过上面的方式,是可以源码依赖的问题,但每次需要调试的时候都这样去改的话,就显得非常的麻烦,还需要把 aar 依赖的方式给注释掉,万一不小心提交了代码,就有可能导致远程无法打包的问题。
那有没有什么方式是在 开发的时候使用 module 依赖,而不改变app 的gradle 文件呢?下面就介绍一种 aar依赖 与 源码依赖快速切换的方式。
二、aar依赖 与 源码依赖 快速切换
在主工程的 build.gradle 文件中,增加如下代码:
allprojects {
configurations.all {
resolutionStrategy {
dependencySubstitution {
substitute module( "com.mei.module:user") with project(':user')
}
}
}
}
上述代码的意思是,以 module 代替 aar 包,则在编译工程的时候,只会把 module 的代码加入编译,而 aar 包的代码不会加入编译。
当然,也可以只在 app 的build.gradle 文件中,加入上述代码,这个时候就可以不用调用 allprojects 方法了,如:
configurations.all {
resolutionStrategy {
dependencySubstitution {
substitute module( "com.mei.module:user") with project(':user')
}
}
}
如果不想使用 module 依赖,就可以 把 注释1 的代码,给注释掉,就可以接着使用 aar依赖了。
三、组件依赖封装
经过 二、aar依赖 与 源码依赖 快速切换 的操作之后,我们可以不用 注释掉组件的 aar 依赖,就可以实现 aar依赖 与 module依赖的 快速切换,但还是需要去修改主工程的 settings.gradle 文件和 build.gradle 文件,还是会存在误提交的问题。
如果我把 所有的操作,都放到一个 gradle 文件中,只在主工程的 settings.gradle 文件中,引入这个 gradle 文件,就可以实现上面所有的操作,并且在找不到这个文件的时候,也不会导致编译流程失败,不就可以解决误提交的问题吗?
下面就来看看具体是如何封装的。
1、在 module 工程中,增加 module 依赖文件
在 module 工程中,增加 user_dependency.gradle 文件(完整路径:/Users/mei/WorkSpace/AndroidProjects/module-user/user_dependency.gradle),在这个文件中,实现 组件module 的 引入和 与aar依赖的动态切换功能。注意,这个文件可以不用加入到 git 管理。
1-1、组件module 依赖
include ":user"
project(":user").projectDir = file("/Users/mei/WorkSpace/AndroidProjects/module-user/user")
1-2、aar 依赖 与 组件module 依赖的动态切换
在 user_dependency.gradle 文件中,增加如下监听:
gradle.addProjectEvaluationListener(new ProjectEvaluationListener() {
@Override
void beforeEvaluate(Project projectObj) {
try {
if (!projectObj.rootProject.extensions.hasProperty("kotlin_version")) {
projectObj.rootProject.extensions.add("kotlin_version", "1.4.32")
}
} catch (Exception e) {
e.printStackTrace()
}
projectObj.rootProject.apply from: "/Users/mei/WorkSpace/AndroidProjects/module-user/mavenConfig.gradle"
println "beforeEvaluate project.configurations=${projectObj.configurations}"
}
@Override
void afterEvaluate(Project projectObj, ProjectState state) {
println "project name is $projectObj"
println "afterEvaluate project.configurations=${projectObj.configurations}"
if (projectObj.name != "app") {
return
}
projectObj.configurations.all { Configuration ->
resolutionStrategy {
dependencySubstitution {
substitute module( "com.mei.module:user") with project(':user')
}
}
}
}
})
- 给 gradle 对象,增加 ProjectEvaluationListener 监听事件
- 在 ProjectEvaluationListener 的 beforeEvaluate 方法中,增加一些组件需要依赖的额外配置,如果没有,可以不用添加。
- 在 ProjectEvaluationListener 的 afterEvaluate 方法中,给指定的工程对象,增加配置信息,如:给 app 工程,增加动态切换 aar依赖 和 module 依赖的 配置。
注意:
- 要把 afterEvaluate 的 Project 参数重新命名,否则在 dependencySubstitution 闭包中,调用 project() 方法会报错。
- 只能在 ProjectEvaluationListener 的 afterEvaluate 方法 给工程增加配置信息,因为在 afterEvaluate 方法中,工程的configurations 配置对象不为空,而在 beforeEvaluate 方法中,工程的 configurations 对象是一个空对象,从而也无法 增加配置信息。
1-3、完整的 user_dependency.gradle 代码如下:
include ":user"
project(":user").projectDir = file("/Users/mei/WorkSpace/AndroidProjects/module-user/user")
gradle.addProjectEvaluationListener(new ProjectEvaluationListener() {
@Override
void beforeEvaluate(Project projectObj) {
try {
if (!projectObj.rootProject.extensions.hasProperty("kotlin_version")) {
projectObj.rootProject.extensions.add("kotlin_version", "1.4.32")
}
} catch (Exception e) {
e.printStackTrace()
}
projectObj.rootProject.apply from: "/Users/mei/WorkSpace/AndroidProjects/module-user/mavenConfig.gradle"
println "beforeEvaluate project.configurations=${projectObj.configurations}"
}
@Override
void afterEvaluate(Project projectObj, ProjectState state) {
println "project name is $projectObj"
println "afterEvaluate project.configurations=${projectObj.configurations}"
if (projectObj.name != "app") {
return
}
projectObj.configurations.all { Configuration ->
resolutionStrategy {
dependencySubstitution {
substitute module( "com.mei.module:user") with project(':user')
}
}
}
}
})
2、在主工程的 settings.gradle 文件中,应用依赖文件
在主工程的 settings.gradle 文件中,应用 user_dependency.gradle 文件:
include ":app"
try {
apply from:"/Users/mei/WorkSpace/AndroidProjects/module-user/user_dependency.gradle"
} catch (Exception e) {
e.printStackTrace()
}
通过绝对路径的方式,应用 user_dependency.gradle 文件。这里增加 try catch 的目的是,即使找不到 user_dependency.gradle 文件的时候,也不会影响整体的编译流程。即 哪怕引用不到 组件module 还可以使用 aar 依赖。
这样,只需要修改主工程的 settings.gradle 文件,就可以实现 组件 aar依赖 与 组件module 的动态切换,而且 settings.gradle 的修改也可以提交,不会影响线上的的打包流程。
当debug的 时候,如果想用 aar依赖的方式,可以把 应用 user_dependency.gradle 文件的代码注释掉就可以了。 当然,也可以在 user_dependency.gradle 文件中,增加一个 开关,表示是否使用 module 依赖,从而控制 module 与 aar包 的动态切换操作。
如:
....
def useModule = true
gradle.addProjectEvaluationListener(new ProjectEvaluationListener() {
@Override
void beforeEvaluate(Project projectObj) {
....
}
@Override
void afterEvaluate(Project projectObj, ProjectState state) {
if (projectObj.name != "app") {
return
}
projectObj.configurations.all { Configuration ->
resolutionStrategy {
dependencySubstitution {
if(useModule){
substitute module( "com.mei.module:user") with project(':user')
}
}
}
}
}
})
思考与扩展:
上面的操作,是否可以封装到一个插件中,这样只需要在 主工程中 提供一份 配置信息,就可以动态控制 aar依赖 与 组件module 依赖的动态切换。本地调试也会更加的方便快捷。
|