一直想学习下模块化开发一个App
-
让一个App分成n个单独的模块
-
每一个插件模块由一个小组单独开发,最大限度解耦
- 每一个小组只负责该插件模块的开发、代码合并
- 不用再担心整个App工程的代码合并,也就不再需要对.Xcodeproj解决代码冲突
- 更重要的是不会因为
所有的业务揉在一起
,导致对全局业务不熟悉的人修改代码时,还需要额外的看懂其他不相关的业务代码
-
解耦到极致后,既可以实现每一个模块的热更新
- 主App只是一个承载众多个插件模块的容器载体
- 提供一些基础功能
- 调用其他插件模块完成其对于业务
- 插件A与插件B之间的沟通
模块化基础、从抽象隔离开始
- 假设在MainViewController要push到一个显示新闻列表的NewsListViewController
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
|
-
改进上述MainViewController直接依赖NewsListViewController的方法
- 使用抽象接口隔离
- 同一层依赖接口
- 各层之间也依赖接口
- 使用容器管理接口与实现类的映射关系,可配置化
- 使用一个
标识符
来代替具体的ViewController类- BaseViewController pushWithControllerId: 一个NSIntger枚举值
- 模拟URL Scheme跳转App的思路
- 使用抽象接口隔离
抽象接口 + 容器注入
- 抽象接口定义:显示新闻列表
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
|
- 接口实现类,具体怎么样显示新闻列表
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
|
- MainViewController依赖一个容器获取接口实现类对象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
|
|
- 中间容器,只是随便写的例子
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
|
1
|
|
这样的话就能够做到:
- 那天想切换新闻显示列表的控制器,直接修改容器中接口配置的实现类
- 需要单独抽出MainViewController到其他工程,因为没有任何的具体类依赖
还有之前使用类似URL Scheme
来替代 NewsListViewController
就不细说了,可参考前面的文章.
总的来说,模块化设计的基础就是 面向抽象
模块化进阶一、使用单独的静态库工程
提供子模块功能,然后再通过CocoaPods自动下载导入
-
静态库提供的形式
- 以
.a + .h
形式提供 - 以
.framework
形式提供- 直接提供给别人一个单独的framework文件即可
- 可以更好的打包资源文件
- 还可以通过 CocoaPods 来实现像第三方框架那样集成
- 参考
pod lib create
- 参考
- 以
-
一个完整的App最后是由n个单独屏蔽了内部实现的静态库合并起来的
- 静态库A: 提供显示新闻列表
- 静态库B: 提供商品列表
- 静态库C: 提供支付
- 静态库D: 等等…就是一个单独的业务功能模块
- 再也会产生 .XcodeProj文件产生代码冲突了
- 每一个静态库使用一个单独的podspec,作为一个pods源
-
将所有的子功能模块做成
私有的git库
,然后使用CocoaPods导入
- CocoaPods中podfile文件中的一些配置属性含义
1
2
3
4
5
|
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
|
- 关于使用CocoaPods开发 static framework 的步骤可参看之前的文章.
模块化进阶二、使用单独的子App
提供子模块功能
- 主App依赖n个子App完成对应的子功能模块
-
核心是根据
URL Scheme
来完成App的跳转- 可参考开源类库 JLRoutes 封装的复杂性URL Scheme跳转
- 未按照则跳转AppStore下载安装
-
多个子App的好处与坏处
- 每一个单独的子App,可以单独的测试、发布
- 坏处那就是App太多了…
列举下JLRoutes的简单用法
- App启动时注册URL Scheme的回调处理
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
|
- 当前App被打开时的回调函数,使用JLRoutes处理当前(iso9+)
1
2
3
|
|
- 当前App被打开时的回调函数,使用JLRoutes处理当前(iso9之前)
1
2
3
|
|
更多的使用还是要项目用到的时候再去看了…