CocoaPods最佳实践探讨
jopen
10年前
近期在项目中首次使用了CocoaPods。从软件工程的角度来看,我对目前常见的CocoaPods使用方法有些意见,建议做一些改进。先说一下我建议的最佳实践,后面再分析为什么要这样做。并且希望大家根据自己公司的情况,讨论一下这几项建议是否合理,一起搞出一份真正的“最佳实践”。
CocoaPods的常见使用方法参见唐巧的文章《用CocoaPods做iOS程序的依赖管理》。在他的基础上,我提出几条补充。
1. CocoaPods生成的Pods目录*不*加入.gitignore,也就是说,第三方库的源码或binary要和产品代码一起,提交到公司内部的版本控制系统上。每次修改Podfile并执行pod update后,把Podfile、Podfile.lock、Pods目录下的改动一并签入。
2. 保证在任何时候只签出一次代码就能直接编译执行,不需要执行pod命令,甚至可以不装CocoaPods就能参与开发。
3. Podfile里所有的库使用精确版本号,不使用任何’~> 1.0', ‘>= 1.0'之类的版本号语法,只使用精确的版本号如'1.3.2'。
4. 在项目开发过程中,可以每隔一段时间使用pod outdated命令手动检查各第三方库是否有更新。如果发现某个库有新版本,去第三方库主页查看更新记录,并对版本变动做评估。如果确认有必要更新到最新版本,则修改Podfile里的版本号到最新版本,执行pod update。
5. 如果两个人同时修改了Podfile,第二个人git pull后发现有conflict,resolve顺序是:不动其他文件,先手动resolve Podfile的冲突;然后执行pod update;如果仍有冲突,可以用git reset把Podfile.lock和Pods目录恢复原状,再次执行pod update。此时应该没有pod相关的冲突了。
------------------------------------
以下分析常见CocoaPods用法的问题,首先看CocoaPods官网上的示例Podfile。
source 'https://github.com/CocoaPods/Specs.git'
pod 'AFNetworking', '~> 1.0'
这两行的含义是,使用github上的pods spec,安装AFNetworking 1.x系列最新的那个版本;如果AFNetworking还依赖于其他库,自动安装合适的版本。
假设现在我们的项目中要用到第三方库XYZ,开发流程大致如下:
1. 项目创建者张三在自己机器上安装好CocoaPods。
2. 张三执行pod init,在Podfile里添加代码 pod 'XYZ', '~> 1.0'。执行pod install,把Podfile和Podfile.lock签入代码管理,Pods目录添加到.gitignore。
3. 项目开发人员李四安装好CocoaPods。
4. 李四签出代码,编译,发现pod报错。于是执行pod install后,重新编译通过。
这样的CocoaPods使用方法可能引发很多异常情况。考虑第一类场景:
1. Github突然被盾了(曾经发生过)、或公司的外网出口挂了,李四无法成功执行pod install,因此只能眼巴巴的看着项目代码,无法编译。此时张三说,把我本地的Pods目录都拷给你一份吧,虽然这样拷来拷去容易出错,但暂时先这样临时解决吧。
2. Github突然被盾了,公司的持续集成服务器上无法执行pod install,也没法给服务器拷一份Pods目录。于是连续多天无法用持续集成。
3. XYZ开发者在修改代码时,从git上删除了最新版本的tag,并重新加tag到另一次commit上。于是张三和李四得到的XYZ代码是不同的。(虽然AFNetworking开发者很有经验,不太可能出这种错,但其他小的第三方库就不一定了。)
4. 五年后,早就没人使用古老的iOS 7了。XYZ开发者认为该库是针对iOS 7的,技术已经太陈旧,于是从Github上删除了该项目。(还好我们三年前就不再用这个库了。)但某一天公司有个新项目,想参考以前的代码。当打开代码执行pod install时,发现Github上已经没有XYZ库了。
以上情况可以归结为:你的代码是否可用严重依赖于别人。你从公司的版本控制系统上获取的代码不能直接编译,还依赖于世界各地很多其他人是否正确配置了他们的代码,还依赖于Github等git服务商是否可用,等等。在极端情况下,会有灾难性后果。
再看第二类场景:
5. 在我们项目的开发过程中,XYZ最新版本是1.4。一年后,我们重新打开旧的项目代码,执行pod install,获取到XYZ 1.x系列的最新版本1.7版。在XYZ 1.4到1.7版本之间,改变了一些接口和实现,我们的项目代码很有可能无法编译,或无法正确执行。
这里的问题是:常见的版本号写法'~> 1.0’会在pod install或pod update时检查版本更新,随时将第三方库升级到1.x系列的最新版本。对正在开发的项目来说,经常升级第三方库是可以的。但对已经发布的产品代码,这个变动是不可接受的。已发布的版本必须要有一份固定不变的代码,否则配置管理就失去了意义。
还有第三类场景:
6. 张三的CocoaPods安装的很早,和李四机器上的不是同一版本。这两个版本的CocoaPods对依赖规则的resolve算法不同,因此李四 pod install失败,无法下载到和张三相同的第三方库代码。这是真事,两周前我们刚刚遇到了,后来解决方法是所有人都强制安装某个旧版本的 CocoaPods。
这里的问题是:CocoaPods作为开发工具链中重要的一环,它的质量是否有保证?CocoaPods不是苹果官方的工具,也不是像git那样由极富经验的人组织设计开发,我们能否信任它的版本兼容性?具体来说,即不管用什么版本的CocoaPods,pod install后得到基本相同的第三方库。我们看到最近已经出了一个bug,如果时间再长点,三年后的CocoaPods会不会跟今天有较大差异?
对这个问题的一个解决方法是要求所有项目成员安装相同版本的CocoaPods,甚至安装相同版本的Ruby。但一个人需要同时参与多个项目的怎么办?问题的根源还是没变。
------------------------------------
基于以上分析,我提议的“最佳实践”解决了以下问题。
* Pods目录签入到版本控制系统,使产品代码没有外部依赖,不管什么时候都能从公司内网获取一份可直接运行的代码。
* 已发布版本的产品代码永久固定,不会随时间而变化,方便追踪问题和存档。
* 不要求项目成员装同样版本的CocoaPods,甚至可以不装CocoaPods。降低测试、设计人员使用代码的难度,也避免了CocoaPods本身兼容性引起的问题。
来自:http://weibo.com/p/1001603800875490492754
来自:http://weibo.com/p/1001603800875490492754