1 iOS资源拆分与模块化

  对于iOS,很多App已经注意到图片会散落在各个地方,于是会把图片、配置文件、xib按照模块进行归类,放到各自的bundle包中。做得最好的,是一家电商App,会在App包中的一级目录下面,看不到任何图片,而只有若干bundle,如图9-18所示:

  

android项目拆分模块后导致包体积增加 模块化拆分_jar包

  图9-18 某款App包中,对资源进行了模块化拆分

  只对资源进行模块化拆分是远远不够的。一定要对代码进行模块化拆分。把不同模块的代码放到各自的GIT仓库中,这样各个部门只对各自GIT仓库中的代码负责,而不会产生代码级别的依赖,如图9-19所示:

  

android项目拆分模块后导致包体积增加 模块化拆分_App_02

  图9-19 iOS模块化架构

  在iOS,我们可以使用.a文件进行模块化拆分。把每个模块都以.a文件的形式嵌入到MainApp这个主模块中。

  但是.a文件不能动态下载,所以也就不能使用类似于Android的插件化思想。要想动态更新模块,还要另辟蹊径。

2 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所示:

  

android项目拆分模块后导致包体积增加 模块化拆分_App_03

  图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模块的代码,但是却没有权限修改。

[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]