一、为什么要组件化?组件化有哪些好处?
网上提到的组件化的好处有很多,这里我就仅列举几个比较明显的好处。
1.代码隔离,实现被动解耦
情景a 小王想实现一个右上角有“X”号的dialog,但是他发现基础UI库里dialog没有这个按钮,于是小王想偷偷在基础组件库里写一个tag,用于标记dialog是否右上角有“X”号。
(组件化前)小王偷偷写入成功,大家纷纷效仿小王,最后基础库里的dialog一共有十几处tag用于标记状态。后来,UI大改版,大家发现这个dialog代码过于复杂只能重构。
(组件化后)小王发现基础库的代码是远程依赖,自己并没有修改权限,只好作罢。他通过继承的方式,写了一个属于自己模块的dialog。
情景b: 小张是一个邋遢的人,他写代码从不一口气写完。有一天,小张重构了BaseFragment,但是他写了一半,项目无法编译就提交了,而且他还请了十天的假。
(组件化前) 项目组正在紧急修复一个bug,但是发现怎么也无法编译成功。经查,是小张改了BaseFragment,改的异常复杂,大家还不敢修复,然后又联系不到小张。最终导致项目delay了一个星期。
(组件化后) 项目组一直依赖的是maven库的上版release包,base库虽然代码不能编译,但是app并不直接依赖源码。项目正常推进。
情景c: 小李和小王分别在开发两个模块,小李发现小王im聊天类写的非常的出色,所以准备直接引用小王写的类。但是小王准备对该模块进行升级
(组件化前)两人都愉快的开发,直到上线的那天,小李发现自己im消息加载不出来头像,于是他甩锅给小王。后来两人为此闹的不可开交。
(组件化后)im属于基础组件,要求所有暴露在外的接口必须保持不变。小王升级了组件以后,对小李没有任何影响。
2.工程有了层次感,更容易找到自己的“一亩三分地”
情景a:小刘是一个新来的同学,他接到一个需求,说要给视频直播间加一个dialog。
(组件化前)小刘一顿操作,给直播间一个按钮加了一个dialog,但他不知道音频直播间也在用这个模块,后来线上出现了大批崩溃。
(组件化后)小刘通过名字迅速找到了LiveComponent模块,因为AudioLiveComponent是另外一个模块,所以修改了并没有产生影响。
3.组件化后的模块就像摆在货架的商品,其他app也可以快速集成使用
情景a:A公司日益壮大,一个App已经无法满足公司的雄心壮志,A公司决定要写一个新的以直播为导向的app
(组件化前)程序员们开始疯狂从原有的app上复制代码。从基础框架、网络请求、图片加载 到 数据库、原子参数。后来服务端决定对接口进行升级,程序员们又开始一个一个项目的修改代码
(组件化后)程序员只参照文档 一行gradle一个组件,迅速搭建了app架子。服务端进行接口升级后,各app仅仅把自己依赖的版本号进行升级,就完成了整个app网络请求的改造。
二、组件化长什么样子?有哪些规范?
1.组件化一般分为:
App壳:不参杂任何逻辑,只是把各个业务组件整合在一起。
业务组件层:承担业务功能,不可复用,程序员日常迭代的地方。
功能组件层:封装一些基本的功能,包括日志、分享、登录等。一般不进行修改,供上层业务调用。
基础库:非常基础的库,能干的事情较单一,并且不承担任何业务逻辑。
下图以类似“美团app”为例
注意:图中的依赖关系是自上而下的,同级之间禁止依赖。
2.那组件化的代码又是什么样子呢?以为做的个人app为例
我的项目中有:大厅、直播、彩票等上层模块。接下来是网络请求、基础base架构模块。他的文件结构是这样的
项目是不是看起来清新又直白。这就是组件化的魅力。
三、利用阿里云效搭建自己的组件库
0.创建一个组件
a:通过Androidstudio可以为我们自动创建一个组件。
b:我们一般选择Android library
c:然后起一个名字,模块名我比较喜欢加Component(为了和基础组件区分),包名则省略这个后缀。
d:然后我们重新build一下,新模块就建立好啦,模块有一个三道杠的标示。
1.进入阿里云效,选择制品仓库,选择maven仓库。
根据提示配置gradle
步骤一:请在build.gradle中设置仓库的访问凭证。
group '[GROUP_ID]'
version '[VERSION]'
def artifactId = '[ARTIFACT_ID]'
apply plugin: 'maven'
uploadArchives {
repositories {
mavenDeployer {
repository(url: 'xxxxx') {
authentication(
userName: '***',
password: '***'
)
}
snapshotRepository(url: 'xxxxx') {
authentication(
userName: '***',
password: '***'
)
}
pom.version = '$project.version'
pom.artifactId = '$artifactId'
pom.groupId = '$project.group'
}
}
}
步骤二:设置仓库下载配置
配置
allprojects {
repositories {
maven {
url 'https://maven.aliyun.com/repository/public'
}
maven {
credentials {
username '***'
password '***'
}
url 'xxxx'
}
maven {
credentials {
username '***'
password '***'
}
url 'xxxx'
}
}
}
但是我不听他们的建议,这边我介绍一种比较方便的配置方法:
在模块的build.gradle里加入
ext {
isRelease = false
componentVersion = '0.0.1'
}
在下面的任意地方加入(因为gradle是按顺序编译的,引用必须要放在ext之下)
apply from: "publish.gradle"
这项目文件夹下创建一个publish.gradle
apply plugin: 'maven-publish'
publishing {
publications {
debug(MavenPublication) {
groupId maven_component_groupId //gradle.properties里写入对应的值
artifactId [project.name](http://project.name/)
version "${isRelease ? componentVersion : "${componentVersion}-SNAPSHOT"}"
artifact("$buildDir/aar/${[project.name](http://project.name/)}-debug.aar")
}
}
repositories {
maven {
url "${isRelease ? maven_release_repo : maven_snapshots_repo}" //gradle.properties里写入对应的值
credentials {
username maven_user //gradle.properties里写入对应的值
password maven_password //gradle.properties里写入对应的值
}
}
}
}
这样,我们每次升级版本的时候,只用修改对应模块build.gradle里版本号就ok了
然后我们依次执行下面两行命令,将模块推送到远端:
./gradlew :MusicComponent:build
./gradlew :MusicComponent:publish
然后我们在引用模块的时候,只需要在上层模块build.gradle
implementation "${maven_component_groupId}:MusicComponent:0.0.1-SNAPSHOT"
这样我们就实现了远程依赖。接下来,我们只要一步一步更改版本号就可以完成组件升级。