美文网首页Android收藏集Android架构Android
Android:项目模块化/组件化的架构之路(一)

Android:项目模块化/组件化的架构之路(一)

作者: 码途有道 | 来源:发表于2019-01-21 17:11 被阅读81次

前言

在Android开发中,随着项目的不断扩展,项目会变得越来越庞大,而随之带来的便是项目维护成本与开发成本的增加!每次调试时,不得不运行整个项目;每当有新成员加入团队时,需要更多的时间去了解庞大的项目。。。而为了解决这些问题,团队通常会将项目模块化,以此来降低项目的复杂度和耦合度,让团队可以并行开发与测试,让团队成员更加专注于自己所负责的功能模块开发。。。

对于一些大厂如BAT或者美团等这些大型互联网公司,都会自己造轮子,实现项目模块化。而对于中小型公司,限于成本因素,一般都是选用这些大厂造的优秀的轮子来进行项目模块化。本文以及后面一系列文章,将向大家分享我在项目模块化中的实践经验。我的项目模块化方案主要借鉴于饿了么微信美团的模块化技术文章,如有建议,欢迎提出!

模块化需要做什么

首先,在开始项目模块化之前,我们必须要明确模块化需要做些什么?这就等于写书之前必须得有个总纲,否则越写到后面,越是混乱。以下是我认为在模块化时需要注意的几个问题:

  • 如何拆分项目
  • 模块之间的通信
  • 模块内的代码隔离
  • 模块在调试与发布模式之间的切换

在明确了项目模块化中需要解决的问题后,我们需要选定一个优秀的组件化开源框架。在本方案中,我选择阿里的ARouter,也是目前比较流行的组件化框架之一,大家也可以选择其他开源框架。ARouter的具体使用本文就不在介绍了,大家可以在网上自行搜索,下面开始设计项目模块化的架构。

一、如何拆分项目

在这里插入图片描述

三、模块内的代码隔离

虽然在模块化时,我们已经将业务拆分成了一个一个单独的module,但是有的业务实在是庞大,即使单独拆分成一个module,仍然有些臃肿。但是如果将业务module继续拆分成单独的子module,又会显得过重。此时我们就要开始寻求比module更小一级的粒度,这一点《微信Android模块化架构重构实践》中给我们提出了Pins工程的思路。

pins结构目录pins结构目录

如上图,我们可以在module中构建粒度更小的pins工程来拆分业务,可以更加清晰直观的明确业务内的职责分工,示例代码如下:

  sourceSets {
        def dirs = ['p_imageview','p_progressbar']
        main {
            dirs.each { dir ->
                java.srcDir("src/${dir}/main/java")
                res.srcDir("src/${dir}/main/res")
            }
        }
    }

上述代码做到的是仅仅是分割代码,pins工程之间还可以相互调用。而微信提出的是工程之间没有依赖关系存在,则不可以相互调用,类似于两个module之间,如果没有在gradle中注明依赖,则不可相互调用。所以,有些人就会提出,既然如此,为何不直接拆将Pins工程完全拆分成module?

论坛中开发者们给出的最多的答案是提升编译速度!不过快手的一位资深Android工程师说,微信内部已经放弃了Pins工程,虽然不知道是真是假,不过美团在借鉴微信的Pins工程时,也没有提出代码的完全隔离。就个人而言,我认为Pins工程是module化的一个过渡阶段,当Pins工程的体量达到一定程度时,必须进行完全的module化,所以也没有必要做到Pins工程之间的代码完全隔离,做到以上即可。如果有想实现代码完全隔离的,可以参考《Android Pins 工程结构》

四、模块在调试与发布模式之间的切换

项目开发时,一般提供调试环境与正式发布环境。在不同的环境中,app的有些功能是不需要用到的,或者是有所不同的。另外,在模块化开发时,有些业务模块在调试时,可以作为单独的app运行调试,不必每次都编译所有的模块,极大的加快编译速度,节省时间成本。基于,以上种种原因,我们就必须对项目的调试与正式环境做不同的部署配置,然而如果全靠每次手动修改,当模块量达到数十时,则会非常麻烦,且容易出错。所以我们需要尽可能的用代码做好配置。

首先,来看如何配置module在app与library之间的切换,实现module在调试时作为app单独运行调试。看示例代码,这也是比较常见的方式:

  • gradle.properties中,配置字段isAuthModule,控制auth模块是作为一个模块还是一个app
# true: 作为一个模块 
# false: 作为一个app
isAuthModule=true
  • auth模块的build.gradle文件中作如下配置:
// 获取 gradle.properties 文件中的配置字段值
def isApp = !isAuthModule.toBoolean()

// 判断是否为 app,选择加载不同的插件
if (isApp) {
   apply plugin: 'com.android.application'
} else {
   apply plugin: 'com.android.library'
}
......

android {
   defaultConfig {
        // library 是没有 applicationId 的,只有为 app 时,才有
         if (isApp) {
             applicationId "com.homeprint.module.auth"
         }
         ......
   }
   
   sourceSets {
          main {
              // 作为app与模块时的AndroidManifest.xml会有所不同,在不同状态时选择不同的AndroidManifest.xml
              if (isApp) {
                  manifest.srcFile 'src/main/AndroidManifest.xml'
              } else {
                  // 记得在 main 文件夹下创建 module 文件夹,添加AndroidManifest.xml
                  manifest.srcFile 'src/main/module/AndroidManifest.xml'
          }
   }
}

这样只要我们更改一下,gradle.properties文件中的配置字段,就可以自由实现module在模块与app之间的切换。下面我们再来看下,如何实现app在调试与发布环境时,加载不同的模块,看以下示例:

假如有两个模块,lib_debug 与 lib_release,lib_debug 是只有在调试环境才需要使用,
lib_release 是只有在正式环境才需要使用,以下提供两种方式实现

方式一:
 if(mode_debug){
     implementation project(':lib_debug')
 }else{
     implementation project(':lib_release')
 }


方式二:
 debugImplementation project(':lib_debug')
 releaseImplementation project(':lib_release')

以上两种方式,方式一类似于上述的模块在 app 与 library 之间的切换,方式二是使用 gradle 提供的方法实现

推荐文章

《Android:项目模块化/组件化的架构之路(二)》
《Android:超详细的本地搭建maven私服以及使用Nexus3.x搭建maven私服的讲解》
《美团外卖Android平台化架构演进实践》
《微信Android模块化架构重构实践》
《Android工程模块化平台的设计》
《Android工程模块化平台的设计(整理优化)》
《Android Pins 工程结构》
《pins工程及自动生成文件夹》

相关文章

网友评论

    本文标题:Android:项目模块化/组件化的架构之路(一)

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