本文将以模块化开发的场景作为切入点(基础架构组请将每个组件理解为一个独立模块) 首先,模块化开发这个普通的技术点我不打算再讲了,而且随着移动端技术越来越成熟,也没必要再去讲一些过时的东西了。
如果你还不懂什么是模块化开发,可以查看我2016
年写的博客:《Android业务组件化开发实践》 https://kymjs.com/code/2016/10/18/01/
首先,这是一篇有门槛的文章,如果你们是只有两三个人的团队,那建议还是别折腾了,太浪费时间。如果是比较大的团队而且项目模块化已经完成了的,那还是可以考虑一下的,毕竟可以节省出来不少模块间联调与跨模块沟通的时间。
模块间联调
事实上我们的模块独立性已经做的非常好了,可以做到每个模块的增删,代码零改动,一行都不需要改。原理请见这篇文章:《优雅移除模块间耦合》
但不可避免的,还是有三四个强业务模块,必须依赖全局Service
才能工作的。
还有就是某些模块虽然不依赖外部模块,但需要一些全局信息,例如id
、用户名
这种。但是如果使用mock数据,又会增大工作量,开发不愿意做。
解决办法其实很简单,Android Studio
是支持工程compile
module
的。如何做?来看张图:
在setting.gradle
文件中,可以指定一个project
位置,这里就可以将一个外部工程中的模块导入到APP
工程中了。
然后这个useFeature
,通过在local.properties
文件中配置,就可以达到每个人修改自己的模块不会影响到其他人了。
顺带一提,也有另一种实现方案是直接将工程中的module
单独作为一个git
仓库,然后在外层(工程级)仓库的.gitignore
中配置忽略掉module
。这样在本地看来就是一个工程级仓库中包含了多个module
仓库。这种方式也可以达到目的,但我个人不推荐使用这种方式。
让模块引用与aar引用互斥
解决了前一个问题,在模块联调与源码修改的时候是非常方便了的。但是实际开发中,如果你直接这么做,一定会碰到有类冲突的情况。
举一个例子:
base
模块是每个模块都会依赖的,此刻base
被打为了一个aar
包,在使用的时候直接compile
。
login
模块依赖了base
模块。
此时如果我想调试base
模块,用上面的方法把base
的源码导入,就会发生,项目中不仅依赖了base
的源码,同时还引入了base
的aar
,就会造成类冲突。
解决办法也是有的,就是本节标题:让模块引用与aar引用互斥。
可以通过自定义插件的形式,定义一个特定的关键词,比如像atlas
就定义叫bundleCompile
。在编译的时候,让这个bundleCompile
继承自compile
,并检测到如果setting.gradle
文件中引入了module
的源码就排除掉module
对应的aar
。
写gradle
插件代码太长了,又是得继承指定类,又是得按照编译流程来麻烦的要死,其实还有一种简单的办法,就是直接在gradle
脚本代码里面自己定义一个方法,方法名叫bundleCompile
,也可以达到同样的目的。
防偷懒,我就只贴截图了,自己动手敲一遍吧。
组件平台建设
组件平台建设,这其实是一个企业级开发很重要的点,也是很多人所很难想明白的点。
就像我前面说的,如果你们是只有两三个人的团队建议别折腾了,没必要,口头约束比什么事都写下来要快很多,而且很方便。但如果是比较大的团队可能有什么事你去跟每个人说一遍的时间,都得花一天时间了。
现在每个公司应该都会有所谓的:架构组、基础组、移动横向组,这样的部门。在开发与日常工作时他们通常是做一些面向开发者的事情,例如网络统计、WebView(web容器)、统一配置管理这种的功能。
放大后,我们从宏观去看,其实每个应用的一个模块,也就是前面提到的一个基础功能,那么这种基础功能是否可以对外提供呢,就像一个网页一样,我告诉一个路由scheme
你就打开我指定页面就好了,我告诉你一个接口,你就调我给你的接口对象就好了。
想做到上面的点就很依赖基础设施平台。由于原本公司就有很完善的基础设施平台这是先天优势(感兴趣的可以看一下这个PPT),那么基于这个平台,再去建设基础组件平台就变得非常容易。下面详细说一下几个重要的点:
- 组件的构建很重要,应当是统一由后端构建并直接上传至内部
maven
仓库。这样避免了开发人员手动打包过程中,测试包通过的包和正式包不一致的情况。如果是后端打包,可以直接精确到某次git commit
保证测试的包就是最终发布的包。 - 平台具有版本提示作用,每个版本做了什么,当前最新版本是多少,当前应用中接入的版本是多少,当前线上某个版本接入的某个模块是哪个版本的,这些信息都一应俱全。任何一个有权限的人都可以很清楚的了解到这些细节信息,保证出意外时拥有修复的能力(例如模块的热修复)。
- 模块的测试与发布。前面我也说了,我们几乎所有模块可以做到动态增删不用修改代码。那么测试人员就可以通过远端直接拉取某个线上版本,将那个应用中指定模块给
update
或者配合exclude
,通过控制变量来测试这个已经release
的包是否因为此次模块改动造成问题。 - 线上事故记录。难免有测不到的
BUG
被发布,那么这个问题是哪个版本的应用,哪个版本的模块,问题是否在新版本已经修复过,是否是因为某些特殊接入环境造成的。这些信息也是可以统计到平台内,作为快速自查手册,以避免开发人员多次被同样的事情给打断。
自动版本号
自动版本号的实现网上有很多种办法,这里我讲一下我的实现方法。在gradle
执行上传aar
的时候,可以去远端maven
仓库读maven-metadata.xml
这样的一个文件。他里面记录了当前aar
的各个版本以及最新的release
版本的version
。通过xml
解析,取到后对这个版本做+1
,就得到了新版本的版本号。
具体代码就是一个URLConnection
去访问那个xml文件,然后解析,这里就不贴代码了,相信如果你能看到这里,这种代码你也是能写出来的。