Android组件化架构实现(二)

本篇文章开发一个组件化架构的Gradle Plugin。
插件的作用:
1.每个Module之间实现真正的解耦。
2.在开发阶段每个Module都可以在不经过任何配置的情况下独立运行。

Android组件化架构实现(一)
自定义GradlePlugin
GitHub地址

1.每个Module之间实现真正的解耦。

最初Module之间的依赖是在build.gradledependencies{}进行配置,这样Module之间的类就可以相互调用,虽然在要求上是不允许的,但是没有在编译阶段解决这个问题,没有实现真正的解耦,留下了误操作的隐患。

普通依赖形式.png

在开发阶段使用这个插件可以实现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

项目插件的结构.png

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提高开发调试速度。

Android组件化架构实现(一)
自定义GradlePlugin
GitHub地址

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,607评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,047评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,496评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,405评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,400评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,479评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,883评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,535评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,743评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,544评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,612评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,309评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,881评论 3 306
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,891评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,136评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,783评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,316评论 2 342

推荐阅读更多精彩内容