对于iOS,很多App已经注意到图片会散落在各个地方,于是会把图片、配置文件、xib按照模块进行归类,放到各自的bundle包中。做得最好的,是一家电商App,会在App包中的一级目录下面,看不到任何图片,而只有若干bundle,如图9-18所示:
图9-18 某款App包中,对资源进行了模块化拆分
只对资源进行模块化拆分是远远不够的。一定要对代码进行模块化拆分。把不同模块的代码放到各自的GIT仓库中,这样各个部门只对各自GIT仓库中的代码负责,而不会产生代码级别的依赖,如图9-19所示:
图9-19 iOS模块化架构
在iOS,我们可以使用.a文件进行模块化拆分。把每个模块都以.a文件的形式嵌入到MainApp这个主模块中。
但是.a文件不能动态下载,所以也就不能使用类似于Android的插件化思想。要想动态更新模块,还要另辟蹊径。
家大业大,子女多了,以后就要考虑分家的事情,大家各过各的,出了问题尽量自己搞定。
公司大了,也会面临同样的问题,我们会把App按照模块进行拆分,代码按照模块拆分到不同的GIT仓库中,不同部门负责各自不同的模块,他们会对自己的模块负责。
如果还按照之前的做法,把模块按照Package进行划分,看起来也不错,但是这样做会有问题。比如说发版时间为1月14号,但是A部门负责的A模块却延期了,难道我们要延期发版吗?那不行。
所以我们要把A模块从主项目中迁移出去,A模块会作为一个jar包,主项目会保持对该jar包的引用。这样A模块如果延期了,那么就主项目就仍然保持对A项目原有jar包的引用,这样就不耽误1月14号的正常发版了。
另一方面,各部门如果继续在一个版本库下工作,经常会搞出互相干扰的情况。比如说A提交的代码会导致B编译不过,A提交的代码会冲掉B的代码,A修改了公共方法会导致其他地方都报错。当我们把代码按照模块都拆开了就不会有问题了,A随便提交自己的代码,只会影响自己的GIT仓库,不会祸及他人。
然而问题接踵而至,如图9-20所示:
图9-20 Android模块化拆分示意图
我们看下面这个模块拆分图,有以下几个问题需要解决:
1)ModuleA模块和ModuleB模块共用的类和方法,要怎么处理?
2)ModuleA模块和ModuleB模块共用的资源,要怎么处理?
3)如何能在不同模块间共享数据?比如说全局变量,比如说模块之间页面跳转时传值。
对于问题1,我们要解决代码上的依赖。为此,需要从项目中剥离出一个业务无关的AndroidLib类库。在此基础上,我们可以轻松的把一个模块所涉及的那些Activity转移到另一个模块去。
对于问题2,我们要解决资源上的依赖。
首先是要制定模块的命名规范,所有资源前面都要加上模块名称,这样才能确保资源名称不冲突。
对于公用资源,还是要放在AndroidLib目录下,AndroidLib类库会为每个公共资源生成一个R.id.xxx的对应属性,我们要把这个R文件连同资源、以及AndroidLib目录下的代码一起打成jar包,放到要用到它的MainApp、ModuleA、ModuleB模块中,这样手动打包时才不会出错。
对于问题3,我们有很多手段,来传递数据。
比如说,从ModuleA模块的A1页面,跳转到ModuleB模块的B1页面,传递一些简单类型还好办,如果要传递自定义的实体,就只能把这个实体定义在AndroidLib类库中了。但是AndroidLib类库毕竟是放业务无关的代码,所以不适合存放这样的业务实体类,所以还是尽量不要改动AndroidLib类库。
比较靠谱的做法是,再新建一个存放实体的AndroidEntity类库,这些实体专门用于传递模块间要传递的数据。所有模块都保持对这个类库的引用。
我还见过模块间通信使用JSON文本的,这样就不用在AndroidLib类库中建实体类了。
对于用户身份信息,也就是那个User单例类,也是这么处理,把User类放到AndroidLib类库中。
如果一定要使用全局变量,而且要在不同的模块间读写,也可以这么处理。
接下来说开发人员如何创建自己的工作区。
1)最简单无脑的办法就是把所有的项目都打开,项目之间是代码级依赖关系。ModuleA模块的开发人员只能修改ModuleA的代码,尽管能看到MainApp模块和ModuleB模块的代码,但是却没有权限修改。
项目之间是代码级的依赖关系,那么自动打包脚本就要相应修改,我们要同时编译若干个项目,而且有先后顺序。请参见博客园“谦虚的天下”的文章《App自动化之使用Ant编译项目多渠道打包》[1]。
2)比较高级的做法是jar包依赖的方式,只打开自己部门所属模块的代码。
比如说,对于MainApp模块的开发人员,他们只打开MainApp模块的代码,而把ModuleA模块和ModuleB模块对应的两个jar包,引入项目中。这两个jar包是由ModuleA和ModuleB这两个模块的开发人员生成后上传到MainApp模块的lib目录的。
而对于ModuleA模块的开发人员,则是要打开MainApp模块和ModuleA模块的代码,而把ModuleB模块对应的jar包,引入项目中。因为MainApp模块是宿主(也就是一个壳),所以不得不打开它的源码,才能编译调试代码。
按照这种jar依赖的方式,自动打包脚本就非常简单了,仍然是单项目的打包机制,我们基于MainApp项目进行打包,其他所有模块都事先做成jar包放到MainApp项目的lib目录下。
[1] 文章地址:http://www.cnblogs.com/qianxudetianxia/archive/2012/07/04/2573687.html