1.0 iOS模块化中的问题
前文已经介绍了模块化的流程及一些常见的问题,我们在这里再次总结一下。
在工作中,当我们开始一个新项目的时候,最先考虑的就是模块化工作。
模块化工作的想法是很美好的,可是执行过程中会遇到很多的问题,而这些问题可能会让我们在工作中举步维艰。
工具使用问题。iOS的模块化一般会使用cocoapods工具,这个工具很强大,内容也很丰富,我们想要完成模块化工作,需要建立私有库,编写podspec文件,处理资源,编写Podfile文件,建立本地依赖等等。让团队成员每个人都精通这个工具是不必要的。因此经常会在使用工具中遇到不易解决的问题,从而浪费大量的时间。
xcode设置问题。xcode设置项多如牛毛,很多内容看起来并不直观,需要我们去查阅官方文档来解决。而且这些设置数量多,使用的频率又少,所以难免会出现这样的情况:每个人都遇到的问题,然后各自去花时间解决,然后过段时间遇到相同的问题常常就忘记了,还要花时间去查阅解决,造成资源的重复浪费。
模块间依赖的问题,当你依赖的也是
私有库的其他模块(下文中称为自有模块)
时,开发中可能要同时修改多个模块,这样就会出现在多个工程中切换的问题。规范问题,每个人建立模块的方式可能都不同,包括工程结构,工程设置等等。这样一来,不同的模块可能差异特别大,当跨模块开发或者代码交接的时候,可能就会出现难以解决的问题。
设置的变更修改都是手动修改,有时候难免会因为疏忽,而导致难以发现的错误,当需要处理的模块和依赖较多时,发生错误的概率也会增加。
2.0 编写自动化工具
为了解决这些问题,让团队能够将精力全部集中到业务开发中,特使用bash shell开发一个构建工具,用于自动化处理模块化的过程中遇到的设置及工具使用问题。
工具的地址如下:https://github.com/hardman/AWModularization
使用这个自动化工具你将会获得如下能力:
- 一条命令即可创建模块工程,创建.podspec及Podfile文件,自动安装依赖,工程默认使用静态库,支持Swift和OC
- 一条命令即可拉取之前开发的模块,并且安装好所有依赖
- 一条命令即可自动打tag,自动更新.podspec文件,将工程推送到pod服务器
- 自有模块的列表,将会保存在单独git库中,便于有依赖模块时,可动态加载
- 自有模块的依赖都通过.podspec文件使用local path的方式安装,这样当被依赖的模块也需要修改时,不需要打开多个工程
因此,使用这个自动化工具,你不需要了解cocoapods工具,也不需要处理任何工程和工具设置,可以将注意力都集中到业务开发中。
【注】工具使用静态库作为模块的输出文件。
3.0 工具的使用
3.1 基本使用步骤
- 将工程clone到本地目录
- 打开
tools/config
修改配置文件- modulelistgitaddress.txt:新建一个git库,并将地址保存在这个文件中,地址最好是以
git@
开头。这个git库用于保存所有自有模块名称及地址。 - podspecsaddr.txt:再新建一个git库,将地址保存在这个文件中,地址最好是
git@
开头。这个git库就是你的私有库地址。 - podspecsname.txt:为你的git库取一个名字,保存在这个文件中
- 上述3个文件都只有一行
- dependencypodrepos.txt:这个文件保存你的app依赖的其他
pod repos
,一般情况下保持默认即可,支持多行,每行保存一个地址 - 由于这些配置几乎不会修改,考虑将这些文件提交到你自己的git库中
- modulelistgitaddress.txt:新建一个git库,并将地址保存在这个文件中,地址最好是以
- 执行
./create.sh -n=[模块名] -b=[bundle id] -t=[s|f|r]
即可创建工程- 脚本执行过程中会要求输入一些工程基本信息及所依赖的模块,请认真输入,不要遗漏
- 创建的工程会自动打开,并且可以直接执行
- 创建好的模块文件在:
工程根目录/modules
。 - 例:
./create.sh -n=HelloWorld -b=com.helloworld -t=s
- 模块开发完毕,需要将代码提交到develop分支,然后执行
./push.sh [模块名] [tag]
- 执行push.sh时,模块必须在develop分支上
- 执行成功后,你的模块就已经提交成功,可以通过Podfile文件引用了
- 例:
./push.sh HelloWorld 0.0.1
- 使用
./pull.sh [模块名]
即可下载其他未同步到本地的自有模块- 执行成功后,会自动下载所有依赖的模块,并通过local path添加到模块依赖中
- 例:
./pull.sh HelloWorld
3.2 如何提升模块所依赖其他模块的版本号
有的时候,当前模块所依赖的模块版本升级了,需要修改当前模块的依赖文件。
有2种方法:
- 直接修改文件
- 需要修改的文件有2个,一个是文件根目录的
dependency.txt
文件,文件内记录了当前模块依赖的自有模块
。 -
dependency.txt
文件记录模块版本的格式是:每行一个模块;格式为:模块名@@版本号
,版本号支持~>
前缀,不可带空格 - 另一个文件是
模块名.podspec
文件 - 按照
podspec
文件要求的格式去修改版本号
- 需要修改的文件有2个,一个是文件根目录的
- 使用脚本修改
- 执行命令:
./utils.sh [模块名] upgradedependency [依赖的模块名] [版本号]
- 其中版本号可以为空
- 例子:
./utils.sh LoginModule upgradedependency AFNetworking 3.5.0
- 例子:
./utils.sh LoginModule upgradedependency AFNetworking
- 执行命令:
- 版本号可支持英文字符:a.b.c
3.3 如何在模块工程内使用Swift&OC混编
- 在module工程内创建OC的类文件及swift文件,假设OC类名为 TestOC,swift类名为TestSwift
- 让OC能够访问Swift类
- 只需要在TestOC.m中添加import。例:
#import "模块名/模块名-Swift.h"
。 - 另外需注意的是,TestSwift类必须是public并继承自NSObject。
- 只需要在TestOC.m中添加import。例:
- 让Swift能够访问OC类
- 在 [模块名].h 这个文件中引入你的头文件。例:
#import "TestOC.h"
。 - 在
xcode - build phases - [模块名].h
文件必须在public区域
- 在 [模块名].h 这个文件中引入你的头文件。例:
3.4 关于模块资源文件的获取
- 由于模块都是静态库,所以最终运行到app中后,每个模块的资源文件
(.xcassets, .xib, .png, .jpg, .jpeg, .gif, .txt, .plist, .bundle, .zip, .car)
都是放到:"模块名.bundle"
文件中的,而这个bundle在main bundle
的根目录(这也是要求模块名防止重名的原因之一) - 所以获取图片可以使用
UIImage.init(named: name, in: bundle, compatibleWith: nil)
方法 - 获取其他文件也需要指定bundle才可以
- 开发过程中,获取任何资源都需要带bundle,不能直接使用类似
UIImage.init(named:String)
这种方法,即使是在模块工程内部的代码也不行 - 需要注意的是,静态库的单元测试target是无法获取资源的
3.5 注意事项
- 模块名要防止重复,不但要防止同一个私有库重复,也要防止与其他pod repo内的模块重复
- 依赖库不可产生循环依赖,比如 A依赖B,B依赖C,C依赖A
- 每个模块都有一个develop分支,develop分支的代码总是与最新的tag保持一致。执行push命令时,代码总是在develop分支上
- 开发期间(集成测试前)总是依赖本地模块,每次总是在集成测试前,才会执行push.sh脚本
- 如果当前的开发模块有修改,同时依赖的模块也有修改,则需要先push当前模块所依赖的模块,最后push当前模块。这时候可能需要使用
./utils.sh [模块名] upgradedependency [依赖的模块名] [版本号]
命令修改模块所依赖的模块的版本号
--完--