最近一直在团队推进关于 iOS 模块独立运行相关的事项,想把最近的一些想法和实施情况通过这篇文章做一个记录。
如果在一个项目中,某一块代码足够独立(功能、业务上),就会倾向于将他通过 Cocoapods 抽离为一个 pods 文件。通过一个 podspec 文件描述这个 pod 的信息。
最直接的方式就是把相关文件组织好迁移到一个目录下,通过 podspec 对源码位置,资源位置等信息的描述,完成一个最简单直白的 pod 创建。
并且在 Podfile 中通通过
- pod 'XXX', :path => '~/dev/XXX'
这种方式,集成到主工程进行开发。开发自测完成后通过私有 repo 发布,并且将 Podfile 中的指向版本
- pod 'XXX', '1.0.0'
然后我们就会说,抽离了一个库,项目的代码结构变得更合理更清晰了。
但这么做,在我看来跟在项目里直接用 group 把这些代码区别开来没什么区别,反而要修改的时候还要重新 git pull、pod install 变得更加麻烦了。
因为这么做被分离的代码无法独立运行,而且由于依赖不清晰,没办法共享给其他项目使用,导致这种分离方式是一种伪解耦,该有的益处没有展现出来,修改的时候反倒更加麻烦,这绝对不是我们想要的效果。
由此引出对模块独立运行
个人心目中完美的 Pod 应该在这四个维度上做到最好。
然而要做到这些维度上的最好,需要克服很多问题,接下来慢慢道来。
类似 AFNetworking、SDwebImage 这样的功能型代码,分离的一个只需要确保自己的依赖清晰,被依赖的时候使用方便就可以了。而对于偏业务型的代码就不那么容易了,通常会有界面,还会有各种业务带来的附加产物,例如打点,例如网络库各种规则。
因为功能型代码本身对于以上四点门槛不高,我就不展开讨论了,主要还是展开说一下业务型代码。
推进业务型代码独立运行过程中遇到的一些问题列举:
实施过程中开发了两套工具来解决。均未开源,外网勿搜。下面介绍详细思路。
好不容建了一个独立运行 Pod,要是不小心被不明真相的同学用 path 开发了就糟了。如何避免被 path 模式开发呢?如果是源码模式下,其实是做不到的。所以我们把每个独立运行的 Pod 的产物定位二进制库,静态动态都可,podspec 层面就不允许指向源码,想要修改源码,只能通过独立运行的工程进行修改。
具体操作这里不展开了,如果 podspec 指向的是静态库,而没有源码指向则这个 Pod 理论上不可能不可被 path 模式开发。
而如果通过 Cocoapods 官方建议的
方式创建,则 Pod 代码会存在于 Development Pods 下,而必须在 podspec 中指定源码路径,因此我修改了 pod lib create 的脚手架模板,将 Pod 代码直接放入项目的一个 Group 中,而 Group 对应产物是一个 framework,podspec 直接指向 podspec,外加 Universal 打包脚本就可以啦。
- pod lib create
有同学有疑问了,那源码调试怎么办呢?这个不用担心,既然 Pod 已经可以独立运行,有什么问题需要调试,是都可以在 Pod 工程中进行数据 Mock 来还原问题的,所以主工程只是用来集成,不需要考虑调试问题。
即便是特别特殊的情况,只在主工程能还原,那临时加一下 podspec 指向本地 path 做一下 debug 也是可以的。
Pod 独立运行工程的一大诟病就是时间一长,工程就无法编译通过运行了,并且哪些依赖需要更新,需要详细对比,成本非常高,很多遇到这样情况就会放弃 Pod 工程。
为此 gearmaker 中集成了版本仲裁能力,通过 hook pod 命令,在 pod install 之前,计算出指定客户端主工程最新的依赖全集,在 pod install 时,在这个全集中找到仲裁版本来使用。
这样一来,pod install 后的 Pod 工程所有依赖必然与主工程一致,只需要修改因为依赖更新带来的相关 api 变更即可通过编译正常运行,确保 Pod 工程不会腐败。
所有 Pod 只需要直接依赖 ServiceProvider,由 ServiceProvider 来统一提供服务能力,包括 Pod 工程本身需要的任何能力。比如,路由、打点、网络、从另一个模块获取数据,获取一个 View 对象等,均不需要依赖其他库,直接从 ServiceProvider 中通过内置的 protocol 来获得,并使用。
提供能力的一方对预先放置在 ServiceProvider 中的 protocol 进行功能实现,通过以下方式将自身的能力注册入 ServiceProvider,即可为其他提供能力,而不需要依赖。
注册服务
- [ServiceProvider registService: [XMUserTrack class] withProtocol: @protocol(UserTrack)];
获取服务
- id < UserTrack > ut = [ServiceProvider serviceWithProtocol: @protocol(UserTrack)];
对于新的 Pod 创建,直接使用以下命令创建:
- gearmaker < PodName >
根据命令行提示进行创建即可。创建完成的脚手架直接提供了 ServiceProvider,开发同学直接从 ServiceProvider 中获取服务进行 Pod 开发,开发完成后通过 Universal 脚本生成 framework 上传到私有 repo 中定版本即可直接使用。
来源: https://juejin.im/post/5a3678cff265da4307035980