Aandroid组件化模块化架构

  • 这几年一直忙去项目和家庭,作为快开发10年工程师,经历了移动最辉煌的时代,也经历低落的时段,做过了几万用户-百万等等无数项目,也许将要面临转行等等,在疫情这次大灾难下,让我深深感受我们身处了一个幸福的时代,我们不应该敢于平庸,不能随波逐流,才把最近几年项目中组件化、插件化、热更新、路由、mvp、插拔式服务都会慢慢开源出来,项目代码开源https://gitee.com/applehsp/AndroidHspDemo,model分支,欢迎大家点星,多多评论、多多开源提交建议,支持kotlin、androidx,版主也在学flutter和ios,会分享一些新的博客,网络库地址:
    com.applehsp.http:AppleHttpJava:1.0.0,mvp地址依懒com.applehsp.mvp:MvpKotlin:1.0.7。

  • 模块独立运行

         组件化就是模块分离,模块工程可以独自编译和运行,  首先是清单文件androidmanifest.xml分离,目前大多实现思路无非两套方案:

        1.在build.gradle中通过gradle.properties中定义一个变量,然后控制是否模块(com.android.library)或者app(com.android.applicaito),然后在app工程build.gradle中动态控制添加类库方式。

        2.我的方案通过groovy做一个插件,然后每个工程gradle.properties中RunAlone属性是否运行模块标记,mainmodulename标记主工程标记,如果是app主工程标记运行,脚本过滤非模块动态添加类库。

project.dependencies.add("api", project.project(':' + taskPro.name))

     插件源码是 com.model.buildgradle:model-plugin,已发布到jenter,源码地址https://github.com/apple317/ModelPlugin.git,使用说明如下,将会发布一片如何实现插件、发布jenter、插件源码groovy讲解。

SetUp.1 : 主项目引用编译脚本

                      在根目录的gradle.properties文件中,增加属性:

                      mainmodulename=app

                      其中mainmodulename是项目中的host工程,一般为app

SetUp.2 : 在根目录的gradle文件中配置

    repositories {

            jcenter()
        }
        dependencies {
            classpath 'com.android.tools.build:gradle:3.0.1'
            .....
            classpath 'com.model.buildgradle:model-plugin:1.0.0'//添加组件化插件
            .....
        }
    }

    allprojects {
        repositories {
                .....
        }
    }
    .....

SetUp.3 : 拆分组件为module工程

在非app组件的工程目录下新建文件gradle.properties文件,增加以下配置:

RunAlone=true
component=sharecomponent,other(其他模块)

在app组件的工程目录下新建文件gradle.properties文件,增加以下配置,默认自动添加所有其它组件: RunAlone=true

上面三个属性分别对应

  • RunAlone : 否单独调试
  • component :组件化模式下依赖的组件

SetUp.4 : 在组件和host的build.gradle都增加配置

apply plugin: 'model-plugin'
//注意:不需要在引用com.android.application或者com.android.library
  • 模块跳转通信

       模块通信是组件化中最难的一点,如何做到独立解偶,这里先分享arouter路由实现,然后会在接下来另一个博客分享16年自研发路实现,大体思路跟阿里arouter差不多,一般的话可以直接使用arouter.

      

      如上图在需要地方地址注入,然后需要地方调用如下图:

    

   在这里有个巨坑请注意kotlin和java混编的时候,arouter框架会报各种错误,org.jetbrains.kotlin.kapt3.base.ProcessorWrapper,jdk版本,混编报错等,正确配置如下图,一定要按红线标记重点配置,不然会报错到让人认清不了自我:

     

  • Application离散式注册方案

       模块根本就是互相不影响,互相可以自己实现业务,那么application是app唯一全局单利存活体,平时想初始化推送、图片缓冲、网络配置等等都是在这里做,那么如何业务拆分、独立、解决耦合,目前我查遍大多数网上有两种实现。

      1.网上大多实现思路是在基础application中,通过在主工程注入方式,然后各自模块扩张,这样背离解决耦合,app工程就应该是个空壳原理。

      2.application离散注册,其实原指一个博客文章对我的启发,为什么不再各种模块根据需要插拔注册,然后在基础application中集中通过反射实现,代码如下:

val mAppLifecycles= ArrayList<ApplicationLifecycles>()

    fun getApplicationLifecycles(){
        try {
            val appInfo: ApplicationInfo = getPackageManager().getApplicationInfo(
                getPackageName(), PackageManager.GET_META_DATA
            )
            if (appInfo.metaData != null) {
                for (key in appInfo.metaData.keySet()) {
                    if ("AppConfig".equals(appInfo.metaData.get(key))) {
                        mAppLifecycles.add(parseModule(key))
                    }
                }
            }
        } catch (e: PackageManager.NameNotFoundException) {
            throw RuntimeException(
                "Unable to find metadata to parse ModularAppConfiger",
                e
            )
        }
    }

    open fun parseModule(className: String): ApplicationLifecycles {
        val clazz: Class<*>
        clazz = try {
            Class.forName(className)
        } catch (e: ClassNotFoundException) {
            throw IllegalArgumentException(
                "Unable to find ModularAppConfiger implementation",
                e
            )
        }
        val module: Any
        module = try {
            clazz.newInstance()
        } catch (e: InstantiationException) {
            throw java.lang.RuntimeException(
                "Unable to instantiate ModularAppConfiger implementation for $clazz",
                e
            )
        } catch (e: IllegalAccessException) {
            throw java.lang.RuntimeException(
                "Unable to instantiate ModularAppConfiger implementation for $clazz",
                e
            )
        }
        if (module !is ApplicationLifecycles) {
            throw java.lang.RuntimeException("Expected instanceof ModularAppConfiger, but found: $module")
        }
        return module
    }

  清单文件注册,然后各自模块扩张实现

     

  

  • 模块api提供(可以参考微信方案)

      组件化最核心也是如何通信,模块之间如何通信,最近看过大多数帖子博客以及微信方案,然后我在15年当时方案上升级优化总结,模块各自负责需要对外开发api,这个api组件是所有模块都要继承,如图:

                  

      然后在各自模块实现api对外业务逻辑,如下图:

        

/login/loginserver这个是url,注入到路由之中,那么在调用到是通过path就可以反射找到这个类,然后调用对应业务代码。如下图:

这块有个坑请注意,不要使用arouter中的注解注入autowired,会出现找不到kotlin类。

发布了50 篇原创文章 · 获赞 7 · 访问量 12万+

猜你喜欢

转载自blog.csdn.net/Apple_hsp/article/details/105184617