专栏首页逮虾户Android组件化问题思考

Android组件化问题思考

当项目开始膨胀的时候

当一个工程越来越大,功能越来越复杂之后,成员越来越多的情况下,如何维护一个巨大的安卓项目呢?

第一阶段,大家肯定都是会把公共模块什么的都抽取出来,封装成aar,之后通过maven的方式引入。

第二阶段,引入路由以及spi,把项目打散成一个个子module,然后每个人负责一两个模块之类的,这样就能保证并行开发了。

第三阶段,当项目臃肿到编译速度越来越慢的情况下。这个时候会先抽象一个壳工程,然后把所以的子项模块用aar的方式引入这个壳,之后会把每个业务放在一个仓库内,这样多个业务之间就不会出现代码冲突之类的问题了。

这个时候会出现另外一些更困扰的问题。

  1. 壳工程是不是所有业务仓库都需要拥有一份,那么壳工程代码同步怎么办?
  2. 各个仓库的aar版本问题?不同branch 需要使用不同的aar版本如何做到统一管理?
  3. 万一我要调试别人的仓库了如何调试呢?

遇事不决找轮子

那么有没有现成的轮子可以解决这些工程化之后会碰到的问题呢?

Gradle Repo 容我给大家安利个项目,我们当前项目使用的轮子就是这个。Github传送门

作者对于这个仓库的描述是这样的。

Gradle Repo是基于Gradle写的一个插件,用于管理多个Git仓库,支持方便快捷的切换分支。在根项目中会有一份配置清单repo.xml,用于描述模块来源、工程结构以及依赖关系。

主要做了三件事情:

从各个远程仓库clone代码到指定目录路径下。通过Git的exclude而不是submodule。 动态include模块,并模块间的依赖关系,切换至指定分支。

文字描述上可能还是有些不够清晰哦,我们通过一张作者的图片去分析这个功能。

然后我自己写了个mock的repo.xml的文件,我们通过这个xml来简单说下做了什么。

xml version='1.0' encoding='UTF-8'?>
<manifest>
 
    <substitute project=":module" targetModule="com.a.b:c"/>

    <module name="RouterLib"
        origin="https://github.com/Leifzhang/Router-Android.git"
        srcBuild="false" 
        substitute="com.github.leifzhang:routerLib" />
        
manifest>
复制代码

这个是我根据项目内生成的一个高度相似的模版。

  1. substitute标签代表的是当前项目下的setting内部的project名,其中targetModule代表的是我们需要替换的aar版本。
  2. module 则代表我们想clone的远端的模块,origin代表仓库地址,srcBuild代表当前是否打开依赖,substitute则代表把远端的implementation更换成本地的project。

当项目使用了Gradle Repo调整之后,我们可以随意的拔插我们需要的模块,同时把多个模块仓库组合在一起同时编译。同时在ci上的则还是通过implementation依赖的仓库,我们在开发的时候不会影响到别的业务线的开发,同时在不同的由于每个仓库都是独立的gitlab,所以在branch管理上也会有个天然的优势。

但是这个方案真的完美无缺吗??

其实也不是,那么由于项目散落在不同的仓库内,所以必然会出现一个问题,如何统一管理项目内的aar版本呢??????

不知道各位有没有注意过前一阵子有个老哥写的文章叫JakeWharton评价我的代码像是在打地鼠?。其实jake大神说的configurations.all就是这里的解决方案了。

gradle configurations.all

那么让我给大家简单的介绍下,configurations.all的作用就是强制拉平项目内的maven aar版本号。如果当项目通过implementation依赖引入了不同版本的aar的情况下,会以configurations.all内定义的版本为准,忽略掉项目内使用的差异版本。

configurations.all {
    resolutionStrategy {
        force "com.android.support:appcompat-v7:28.0.0"
    }
}

上面的代码的意思就是,强制项目内的supportv7版本到28.0.0版本上去。

通过gradle plugin升级这个能力

如果简单的使用configurations,还是会出现每个业务模块都需要处理的情况,无法把这个能力收束到一个盒子内,这个时候我们可以考虑通过一个gradle plugin,自定义一个task的方式,对这个能力进行一次拓展。

定义dep版本配置

首先我们需要定义一份远端的和branch版本相关的gradle文件,这个文件内可以定义好我们以前在工程目录下所熟悉的maven仓库的版本。

  dep = [
            fastjson                 : "com.alibaba:fastjson:${fastjsonVersion}",
            //三方控件
            androidSupportV4         : "com.android.support:support-v4:${androidSupportV4Version}",
            androidSupportV7         : "com.android.support:appcompat-v7:${androidSupportV7Version}",
            androidLifecycle         : "android.arch.lifecycle:runtime:${androidLifecycleVersion}",
            androidLifecycleCommon         : "android.arch.lifecycle:common:${androidLifecycleVersion}",
            androidLifecycleCommonJava8    : "android.arch.lifecycle:common-java8:${androidLifecycleVersion}",
            androidLifecycleCompiler : "android.arch.lifecycle:compiler:${androidLifecycleVersion}",
            androidLifecycleExtensions:"android.arch.lifecycle:extensions:${androidLifecycleVersion}",
            recyclerview             : "com.android.support:recyclerview-v7:${recyclerviewVersion}",
            androidSupportAnnotations: "com.android.support:support-annotations:${androidSupportVersion}"
            ]

自定义gradle task

然后我们自定义一个gradle插件,然后生成一个自己的task任务,同步命令被执行的时候,我们就通过接口调用或者git操作的方式去获取远端的gradle,然后更改项目的gralde configurations.all的方式,去吧项目内的aar版本拉平。

class AATask : DefaultTask() {

    @TaskAction
    fun apply() {
        ##伪代码 从远端拉取Dep配置
        //强制更换项目内配置
        forceConfigVersion(project)
    }
    
    fun forceConfigVersion(project: Project) {
        project.subprojects {
            val depModuleSelectorNotations = mutableListOf()

            project.extensions.extraProperties.properties.forEach { key, any ->

                if (any!=null && key!=null&&key.endsWith("dep")){
                    if (any is Map<*, *>){
                        collectDepModuleVersionSelectorNotations(depModuleSelectorNotations, any)
                    }
                }
            }

            it.configurations.all { configuration ->
                configuration.resolutionStrategy.force(depModuleSelectorNotations)
            }
        }


    }

具体详细的内容涉及到公司代码就不和大家详细的展开了,思路核心就是一切三方库的版本以远端的branch作为标准。

总结

本文只是一篇科普文章,并不涉及到任何代码分析,如果有什么得罪的地方,你也打不到我。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Android IO监控 | 性能监控系列

    公司的一款app最近在上架厂商的过程中,被对方指出了IO读写过于频繁,然后不给上架。但是IO读写的操作非常零散,而且很多第三方框架内都会有写入操作,所以就变得非...

    逮虾户
  • Android DiffUtil 封装|深拷贝

    RecyclerView已经逐渐成为一个安卓开发写一个滑动布局必备的控件了,但是项目中用的大部分还是notifyDataSetChanged ,而在方法注释上其...

    逮虾户
  • CameraX 封装二维码扫描组件

    cameraX已经出来有一段时间了,现在已经从alpha版本到现在的beta3版本。其中内部的代码版本跨度特别大,而且资料相对来说只有官方的demo比较可以参考...

    逮虾户
  • Android基础总结(6)——内容提供器

      前面学习的数据持久化技术包括文件存储、SharedPreferences存储以及数据库存储技术保存的数据都只能被当前应用程序所访问。虽然文件存储和Share...

    mukekeheart
  • RPC(五)

    度量是一种直观展示的方式,是管理的依据。当各种运动手环、各种步数记录软件出现时,人们才发现原来自己运动量这么少。通过排行榜上的对比才发现自己的懒惰。看到手机上完...

    小闫同学啊
  • PHP利用递归函数实现无限级分类的方法

    相信很多学php的很多小伙伴都会尝试做一个网上商城作为提升自己技术的一种途径。各种对商品分类,商品名之类的操作应该是得心应手,那么就可以尝试下无限级分类列表的制...

    砸漏
  • Android高德之旅(1)基础地图

    这个系列之前在CSDN上就发了,不过刚开始就因为公司项目忙搁置了,现在转移阵地到简书,希望这次能坚持把这个系列做完。

    大公爵
  • NVIDIA JetPack 4.4来了,NX还会远么?

    终于等到NVIDIA JetPack 4.4发布也就是SDK Manager 1.1

    GPUS Lady
  • 怎么开展接口测试工作

    经过一段时间的磕磕碰碰,终于完成一个项目的第一轮内部测试,接口测试也基本完成。总结如下:

    软件测试君
  • 来聊聊C++中头疼的线程、并发

    在一个应用程序(进程)中同时执行多个小的部分(线程),这就是多线程。多个线程虽然共享一样的数据,但是却执行不同的任务。

    AI算法修炼营

扫码关注云+社区

领取腾讯云代金券