Android组件化架构实现(二)
本篇文章开发一个组件化架构的Gradle Plugin。
插件的作用:
1.每个Module之间实现真正的解耦。
2.在开发阶段每个Module都可以在不经过任何配置的情况下独立运行。
Android组件化架构实现(一)
自定义GradlePlugin
GitHub地址
1.每个Module之间实现真正的解耦。
最初Module之间的依赖是在build.gradle中dependencies{}进行配置,这样Module之间的类就可以相互调用,虽然在要求上是不允许的,但是没有在编译阶段解决这个问题,没有实现真正的解耦,留下了误操作的隐患。
在开发阶段使用这个插件可以实现Module之间的真正解耦,在编译的时候Module之间是没有任何依赖的,在Run Module时期自动添加依赖,这样就可以保证在写代码时期Module之间没有依赖,所以就不能相互调用类。
插件依赖形式.png
2.在开发阶段每个Module都可以在不经过任何配置的情况下独立运行。
组件化的另一个意义就是在开发阶段可以单独运行每个Module,这样可以提高调试运行速度,不需要的Module没有编译,省去编译时间。
但是网上很多文章都是需要更改配置,这样在开发阶段太复杂了,使用当前插件可以使每个Module在不更改配置的情况下直接运行。
每个Module都可以单独运行.png
3.实现组件化Gradle Plugin
1.对于如何自定义Gradle Plugin前面的文章已经写到请点击这里本文就不在说明。
2.在每个Module下面都创建一个gradle.properties文件,这个文件设置的是当前Module作用域内的全局属性,在插件中可以获取。
文件中的标志有三种如下:
#调试的Module
mainName = module_1
#调试Module依赖的libModule
libNames = sub_2_module_1
#当前Module是否Debug模式,当前project的住Module也就是app 不需要这个属性
#如果true那么build.gradle中sourceSets选择debug目录下的文件和资源
isDebug = true
3.项目插件的结构如下图:
如图可以看出
1)app在build.gradle使用apply plugin: 'component_gradle_plugin'插件,gradle.properties中配置当前Module名字mainName=app,依赖库Module名字libNames=module_1,module_2
2)Module_1模块gradle.properties中配置当前Module名字mainName=module_1,依赖库Module名字libNames=sub_2_module_1
3)Module_2模块同上解释一样
4)Sub_2_Module_1模块gradle.properties中配置没有libNames属性,表示他不依赖任何Module
4.插件实现如下代码(代码中有注释)
根据这篇文章创建插件Module,插件在运行时会回调ComponentGradlePlugin类,所以我们在这个类中处理每个Module之间的关系。
public class ComponentGradlePlugin implements Plugin<Project> {
private static final String MAIN_NAME = "mainName";
private static final String LIBRARY_NAMES = "libNames";
private static final String IS_DEBUG = "isDebug";
@Override
public void apply(Project project) {
System.out.println("ComponentGradlePlugin--------- start");
System.out.println("hello apply");
//获取当前Module gradle.properties中的MAIN_NAME属性,这个属性表示当前Module的名字
String mainName = "";
if (project.hasProperty(MAIN_NAME)) {
mainName = (String) project.getProperties().get(MAIN_NAME);
System.out.println(MAIN_NAME + " : " + mainName);
}
//获取当前Module gradle.properties中的LIBRARY_NAMES属性,这个属性表示MAIN_NAME依赖的库,可以是个列表
List<String> libNameList = new ArrayList<>();
if (project.hasProperty(LIBRARY_NAMES)) {
String[] libNames = ((String) project.getProperties().get(LIBRARY_NAMES)).split(",");
System.out.println("libNames : " + Arrays.toString(libNames));
libNameList = Arrays.asList(libNames);
}
//获取当前Module gradle.properties中的IS_DEBUG属性,这个属性表示当前Module是否用Debug目录下的代码和资源
boolean isDebug = true;
if (project.hasProperty(IS_DEBUG)) {
isDebug = Boolean.parseBoolean((String) project.getProperties().get(IS_DEBUG));
}
//获取当前gradle 运行的Module 名字
String currName = project.getName();
System.out.println("currName : " + currName);
//获取当前gradle 运行的Module 名字
String mudule = project.getPath().replace(":", "");
System.out.println("module : " + mudule);
//获取gradle执行task列表
List<String> taskNameList = project.getGradle().getStartParameter().getTaskNames();
System.out.println(taskNameList);
//获取运行的Module的名字,运行时:app:assembleRelease或者:app:assembleDebug
String taskName = "";
if (taskNameList.size() > 0 && taskNameList.get(0).toUpperCase().contains("ASSEMBLE")) {
try {
taskName = taskNameList.get(0).split(":")[1];
System.out.println("taskName : " + taskName);
System.out.println("taskName Arrays : " + Arrays.toString(taskName.split(":")));
} catch (Exception e) {
e.printStackTrace();
taskName = "";
}
}
//如果assemble的Module是app,那么app的isDebug = true,其他的libNames的isDebug = false;
//如果assemble的Module是library 那么library的isDebug = true,其他的libNames的isDebug = false;
if (!"".equals(taskName)
&& !taskName.equals(mainName)) {
isDebug = false;
}
Map<String, String> applyMap = new HashMap<>();
if (isDebug) {
applyMap.clear();
applyMap.put("plugin", "com.android.application");
project.apply(applyMap);
//将main的isDebug = true,build.gradle sourceSets中调试代码起作用
} else {
applyMap.clear();
applyMap.put("plugin", "com.android.library");
project.apply(applyMap);
//将library的isDebug = false,build.gradle sourceSets中调试代码不起作用
}
System.out.println(currName + " : " + applyMap.get("plugin") + " : " + isDebug);
//添加依赖库,如果不是assemble运行是不要添加依赖库的,否则会报错
if (!"".equals(taskName)) {
for (int i = 0; i < libNameList.size(); i++) {
System.out.println("Dependencies add : " + libNameList.get(i));
project.getDependencies().add("compile", project.project(":" + libNameList.get(i)));
}
}
if (project.hasProperty(IS_DEBUG)) {
project.setProperty(IS_DEBUG, isDebug);
}
System.out.println("ComponentGradlePlugin--------- end");
System.out.println();
}
}
4.运行插件查看打印日志
点击run app,查看如下日志,所有依赖的Module都被调用了
Executing tasks: [:app:assembleDebug]
Configuration on demand is an incubating feature.
ComponentGradlePlugin--------- start
hello apply
mainName : app
libNames : [module_1, module_2]
currName : app
module : app
[:app:assembleDebug]
taskName : app
taskName Arrays : [app]
app : com.android.application : true
Dependencies add : module_1
Dependencies add : module_2
ComponentGradlePlugin--------- end
ComponentGradlePlugin--------- start
hello apply
mainName : module_1
libNames : [sub_2_module_1]
currName : module_1
module : module_1
[:app:assembleDebug]
taskName : app
taskName Arrays : [app]
module_1 : com.android.library : false
Dependencies add : sub_2_module_1
ComponentGradlePlugin--------- end
ComponentGradlePlugin--------- start
hello apply
mainName : sub_2_module_1
currName : sub_2_module_1
module : sub_2_module_1
[:app:assembleDebug]
taskName : app
taskName Arrays : [app]
sub_2_module_1 : com.android.library : false
ComponentGradlePlugin--------- end
Incremental java compilation is an incubating feature.
ComponentGradlePlugin--------- start
hello apply
mainName : module_2
libNames : [sub_2_module_1]
currName : module_2
module : module_2
[:app:assembleDebug]
taskName : app
taskName Arrays : [app]
module_2 : com.android.library : false
Dependencies add : sub_2_module_1
ComponentGradlePlugin--------- end
点击run Module_1,查看如下日志,只有module_1和他依赖的sub_2_module_1被调用,这样其他的Module就不会编译占用时间,调试的时间会更快
ComponentGradlePlugin--------- start
hello apply
mainName : module_1
libNames : [sub_2_module_1]
currName : module_1
module : module_1
[:module_1:assembleDebug]
taskName : module_1
taskName Arrays : [module_1]
module_1 : com.android.application : true
Dependencies add : sub_2_module_1
ComponentGradlePlugin--------- end
ComponentGradlePlugin--------- start
hello apply
mainName : sub_2_module_1
currName : sub_2_module_1
module : sub_2_module_1
[:module_1:assembleDebug]
taskName : module_1
taskName Arrays : [module_1]
sub_2_module_1 : com.android.library : false
ComponentGradlePlugin--------- end
总结:
这个插件可以帮助我们在开发阶段约束Module的代码,使每个Module之间调用都必须使用Router。可以在不修改配置的情况下单独运行每个Module提高开发调试速度。