Fork me on GitHub

安卓组件化开发指南系列(一)

安卓组件化开发指南系列(一)

1.前言

为什么要使用组件化?

  • 在以往的开发中,我们都是拿到项目,分几个模块进行开发,而这种方式下的代码耦合会非常严重,修改一处代码可能会牵一发而动全身。
  • 在团队开发大项目的时候,如果每次修改一次,进行整个项目的编译,那样将会非常耗时间,因此组件化允许我们各个组件在开发的时候可以单独编译,打包时候才组装到一个app中。

2.组件化架构图

  • App主工程作为一个app壳,其主要功能就是集成每个业务组件,最终打包成一个完整的app。
  • 各个业务组件之间不作依赖,使用ARouter来做各个业务组件模块之间的跳转,使用EventBus进行各个业务组件模块的通信,在组件开发模式的时候,它以Application存在,可单独运行,在集成时候,它以Library存在。
  • Common库是项目的基础功能组件,封装公共的功能部分,如,第三方加载,网络请求等,供各个业务模块使用,因此它始终以Library的形式存在。

3.App工程下的配置

3.1 创建全局配置文件

在Gradle Scipts文件夹中新建一个config.gradle,其内容大概如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
ext {
//版本号
versions = [
applicationId : ... //应用ID
versionCode : 1, //版本号
versionName : "1.0.0", //版本名称

compileSdkVersion : 27,
buildToolsVersion : "27.0.3",
minSdkVersion : 17,
targetSdkVersion : 23,
...

//第三方库的版本
picassoVersion : "2.71828",
bannerVersion : "1.4.10",
javaxVersion : "1.2",
...
]

dependencies = [
"appcompat_v7" : "com.android.support:appcompat- v7:${versions["androidSupportSdkVersion"]}",
"constraint_layout" : "com.android.support.constraint:constraint-layout:${versions["constraintLayoutVersion"]}",
"runner" : "com.android.support.test:runner:${versions["runnerVersion"]}",
"espresso_core" : "com.android.support.test.espresso:espresso-core:${versions["espressoVersion"]}",
...
]
}
  • 因为每个module的build.gradle文件都有一些属性的配置,当我们版本号修改的时候,我们如果要每个module都对应去修改,那将是很烦的一件事情,于是我们把版本号统一在一个全局的配置文件中,类似java的常量,一处修改,多处生效。
  • 相信大家也都看到了,这个配置文件中不仅有配置的版本号,还有第三方库的版本号,更直接的还有dependencies这个字段,这样做的好处是将第三方库的版本号和导入代码全部管理起来,当我们外界需要引用库的时候,只需要更少的代码就可以实现。(其实这也不是必要的,因为第三方的库一般都只在BaseModule中一次导入就ok了,下面会说)
  • 使用的时候
1
2
3
compileSdkVersion rootProject.ext.versions.compileSdkVersion;
implementation rootProject.ext.dependencies["recyclerview-v7"];
...
  • 项目的build.gradle中引入全局配置
1
apply from: "config.gradle"

3.2 实现组件单独编译运行

我们熟知的是只有Application类型的module才能单独编译运行,而Library类型的module是无法单独运行的,而当我们进行多组件的开发的时候,我们往往只是负责单独的组件,因此我们需要的是开发过程中,可以单独编译运行自己的模块,而打包发布时候,再成为app工程下的一个依赖组件,因此我们需要设置一个开关。

  • 在项目的gradle.properties中设置一个变量
1
isSigleModuleBuild=false; //false表示的是不进行单组件编译运行,true表示的是进行单组件编译运行。
  • 于是在我们的module中就要进行判断了
1
2
3
4
5
6
7
8
9
10
11
12
13
//业务组件Module
if (isSigleModuleBuild.toBoolean()) {
apply plugin: 'com.android.application'
} else {
apply plugin: 'com.android.library'
}
//工程下的主module
implementation project(...) //基础功能模块的依赖
if(!isSigleModuleBuild.toBoolean){
implementation project(...)
// 业务功能模块的依赖
...
}
  • 在这里稍微提一下,我们在gradle.properties*中配置的字段都可以在 build.gradle文件中直接读取出来,不用任何多余的代码。 因为gradle.properties中的数据类型都是String类型,因此我们需要转换成布尔值。每当改完这个值,要同步下项目。

4.BaseModule下的配置

4.1 api 和 implementation的区别

这里稍微提一下这两个命令的区别,因为我们常用的都是implementation。

  • implementation:使用了该命令编译的依赖,对该module有依赖的module将无法访问到使用该命令编译的依赖中的任何程序,也就是将该依赖隐藏在内部,而不对外部公开,换句话说就是该指令的依赖是不会传递的。
  • api:与implementation是相反的,该指令的依赖是有传递性的,一个moduel依赖了另一个module,则相当于不需要再依赖一次被依赖的module所依赖的东西。它与gradle3.0.0之前的compile指令的效果完全一样。

4.2 功能组件下的build.gradle

多组件开发中会出现一种情况,就是业务组件和功能组件中重复依赖第三方库,为了避免重复依赖,因此在BaseMudule中进行第三库的依赖,此处就要使用到前面提到的api命令了。

1
2
3
4
5
6
7
8
9
10
11
12
apply plugin: 'com.android.library'

dependencies {
//在项目中的libs中的所有的.jar结尾的文件,都是依赖
implementation fileTree(dir: 'libs', include: ['*.jar'])
//把implementation 用api代替,它是对外部公开的, 所有其他的module就不需要添加该依赖
api rootProject.ext.dependencies["appcompat_v7"]
api rootProject.ext.dependencies["constraint_layout"]
api rootProject.ext.dependencies["cardview-v7"]
api rootProject.ext.dependencies["recyclerview-v7"]
...
}
-------------本文结束感谢您的阅读-------------

本文标题:安卓组件化开发指南系列(一)

文章作者:AllenYu

发布时间:2018年11月27日 - 23:11

最后更新:2018年11月27日 - 23:11

原始链接:http://yuzeduan.github.io/2018/11/27/安卓组件化开发指南系列(一)/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。