这个部分首先先大概说下pod的一些基本概念~ 然后过一下如果拆分模块的pod。(这篇也是和同事学习的QAQ)
起源 & Gemfile
在没有pod之前其实我们是直接拷贝源码的:
有了pod之后我们可以用pod来引入依赖,避免了手动的繁琐。pod其实是借鉴Bundler(基于ruby的集成工具,对应的是GemFile),cocoapods其实也属于ruby的一个组件。
所以其实Gemfile
和它的lock文件就是锁死了我们工程所需要的gem环境,例如哪些ruby的工具,cocoapods的版本、fastlane的版本、所需要的插件们~
原理
我们在podfile
里面写明我们所依赖的库名,install的时候,pod会从source
里面所有的spec repo
里面去找到我们要的库的podspec
文件,然后通过这个文件里面的url找到我们的库,再download下来。
pod setup
做的事情其实就是把远端的podspec
文件们都clone到本地。
pod update
和pod install
的区别?
pod install
如果你不改podfile,那么每次都是一样的;但是pod update
它会先执行pod repo update
把repo拉一下,如果库升级了,那么会就去下载最新的库,然后更新.lock文件里面的版本。pod update
还可以升级某个指定的库~
Pod命令解析过程
-
命令分析就是解析我们输入的例如
pod install
命令 -
依赖解析算法就类似我们会在podfile里面规定很多依赖的库,但这些库也会依赖别的库,pod里面规定的其实是一个子集,如何保证引用的库不会产生版本冲突,就是这个模块负责检查的(例如A依赖1.0的B,C依赖2.0的B)
P.S 编译的时候会先编译最底层被依赖的库,例如A依赖B,那么就会先编译B生成B的.a文件,然后在编译A
- 工程生成模块其实就是生成那个小白色的工程文件哒(Pods会生成一个工程,我们原工程也有一个工程,所以这个xcworkspace是为了组织这两个工程)
Pod文件
Podfile.lock
是第一次install生成的文件(如果当前木有lock文件),除非podfile变化或者执行了pod update
否则是不会变的。
它记录了需要被安装的 pod 的每个已安装的版本,当团队中的某个人执行完pod install命令后,生成的Podfile.lock文件就记录下了当时最新Pods依赖库的版本,这时团队中的其它人check下来这份包含Podfile.lock文件的工程以后,再去执行pod install命令时,获取下来的Pods依赖库的版本就和最开始用户获取到的版本一致。
如果没有Podfile.lock文件,后续所有用户执行pod install命令都会获取最新版本的依赖库,这就有可能造成同一个团队使用的依赖库版本不一致。
由于sandbox
,也就是pods目录是不由git管理的,那么怎么知道要不要更新本地库呢?在每次pod install
的结束的时候,会自动复制一份Podfile.lock
复制到Manifest.lock
。每次build的时候会执行xcode里面设置的脚本,比较Podfile.lock
和Manifest.lock
的md5,如果不一致就会报错the sandbox is not in sync with the podfile.lock. run 'pod install' or update your cocoapods
。
每个库都会生成一个.a
的framework文件,pods的project会依赖这些.a
文件,然后pods的project也会生成一个总的.a
文件,我们自己的porject会引用pods的.a
文件:
headers
这个目录就是所有组件对外public的头文件~ 并且生成xcode的时候会自动在xcode的build settings
增加这个search path。
repos
文件夹其实是为了防止每次库依赖分析以及install都去访问github的spec,所以在本地clone了一个~ 由于外网pod更新非常频繁,所以有些公司都是自己做的内网映射,保证源不会经常更新,避免经常pod update。如果遇到报错找不到某个版本,但是git上是有的,执行以下pod repo update
更新一下源即可。
cache
是每次pod install的库文件的cache,如果其他工程也恰好需要同样的版本,就可以直接拿copy给它用啦,避免了下载的操作。
P.S. 一个版本的
~>
只是末位可以大于,前面的数字还是要保持一致的,例如1.0.2 ~> 1.0.1
,但是1.1.2 ~> 1.0.1
是不成立的。
Podfile黑技巧
podfile里面可以通过类似key-value的方式设置一些值~
clean
的意思就是install的时候,如果有些库没有用到会清理;share_schemes_for_development_pods
是不是把pod target设置为share;generate_multiple_pod_projects
是将pod生成多个project,工程可以动态检索文件,这样每个pod都是一个project,在build的时候就会动态获取文件,避免了向本地dev pod增加文件,但是编译的时候找不到文件,还必须要pod install以后才可以;incremental_installation
是多project的模式下增量install,当pull代码以后podfile可能会有改变,加入这个参数以后会cache上次的install结果,只有cache版本不一致才会重新走install(下载 & 生成pod target)的流程。
如果有多个source,然后都有同一个库,版本号还一致,但是库实际文件不一样,那么pod会按顺序找到第一个版本拿到然后用,所以不同source如果同一个库内容不一样但版本号还一样就容易出bug。
hook
pre_install
和post_install
也就是pod的开始以及结束,是可以用脚本注入做一些事情的。podfile其实就是一个ruby脚本,可以在里面做一些hook。
Podfile的编写
spec的外部引用就是通过path、git、commit之类描述的依赖,也就是除了用版本号规定的都是,它会根据文件里面找到的版本号加到版本分析的树里面~
subspec
的意思就是只依赖AFNetworking
里面的NSURLSession
这个小一点的模块。
Podspec文件编写 —— 生成自己的库
具体代码如何做参考这个吧:https://zhuanlan.zhihu.com/p/37843887 & //www.greatytc.com/p/1dabeb10c33a
关于本地私有库可以这么做:https://www.cnblogs.com/hs-funky/p/6759977.html
用本地库的方式就是在项目内建一个文件夹,用于放各个模块的代码(如果之前xcode对这些文件有索引可以删掉),然后给他们按照上面的文章里面生成pod(pod spec create 模块名
),然后编写pod spec文件,之后修改本项目的podfile,引用这个本地库通过path的方式,最后pod install
,这个时候xcode是没有这个库里面的文件的索引的,只有pod有,你会在Development Pods
里面看到这个模块,你也可以修改它然后提交也木有问题(因为其实如果你show in finder会发现其实就在你最开始建的文件夹里面)~
小优化
- Q1: 我们如果开发的时候,需要先改
podfile
把自己要改的模块的库的path指向本地,然后执行pod install
,然后修改本地的代码调试并提交测试,测试通过以后,将库推上去,然后打tag,podfile
还原用tag来指明库依赖。
A1: 现在我们公司是可以直接add某个库成为dev pod,然后自动就会把podfile里面的依赖改为本地,并把这个库clone到单独的文件夹让我们修改。
- Q2: 很多依赖的库在github上面,并且引入的库越多,其实编译的代码就越多,github拉取还很慢。
A2: 把三方库都打成静态库,然后放在公司内部仓库,每次install
直接从内网拉取静态库文件,这样减少了传输时间也减少了编译时间。
- Q3: 一份代码,多个target,多个编译schema,但是对应不同的库依赖怎么办呢,比如target A需要某个库但是target B不需要?
- Q4: 如何把主工程定义的宏同步到pod?
A4: 在install的时候为pod添加宏,也就是hook一下pre_install
or post_install