Android组件化架构实现(二)

作者: 码农一颗颗 | 来源:发表于2017-09-27 13:37 被阅读465次

    本篇文章开发一个组件化架构的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地址

    相关文章

      网友评论

        本文标题:Android组件化架构实现(二)

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