pod install的深入理解
CocoaPods是什么?
CocoaPods是iOS平台当前最流行的包管理工具,可以将它理解为一个可以自动部署到项目的组件池,而对应的podfile文件就相当于请求组件的Request。当组件下载到工程后,CocoaPods会自动完成组件集成到现有项目的工作,并完成修改.xcodeproj文件和创建.xcworkspace文件。最终将所有组件统一打包成Pods.a或者Pods.framework静态库,供项目使用。(类似于JS依赖包管理工具npm)
在CocoaPods中,会存在以下几种文件:
- podspec
Pod的描述文件,一般来说表征你的项目地址,项目使用的平台和版本等信息 - podfile
用户编写的对于期望加载的pod以及对应Target信息 - podfile.lock
记录了之前pod加载时的一些信息,包括版本、依赖、CocoaPods版本等 - mainfest.lock
记录了本地pod的基本信息,实际上是podfile.lock的拷贝
大部分开发者最熟悉的cocoaPods指令就是pod install
,那具体在执行pod install时发生了什么呢?
pod install 运行原理分析
当我们运行pod install
时,实际上 发生了下面这些步骤:
- 分析dependency
对比本地Pod和podfile.lock文件中的版本,如果不一致会提示存在风险。 - 对比podfile是否发生了变化,add/remove pod依赖
如果存在 ,会生成两个列表,一个是需要add的pods,一个是需要remove的pods。 - 如果存在remove的,删除remove的pods(会删除podfile.lock里的版本依赖)。
- 添加需要的pods依赖
此时,如果是常规的CocoaPods库(基于git),会先去:
-
Spec下查找对应的Pods文件夹
-
找到对应的tag
-
找到对应tag下面的podspec文件
-
git clone下来代码并copy到Pod目录下
目录结构.png -
运行pre-install hook
- 生成Pod Project
- 将该pod文件添加到工程中
- 添加对应的framework、.a库、bundle等
- 链接头文件,生成Target
- 运行post-install hook
- 生成podfile.lock ,之后生成文件副本mainfest.lock并将其放在Pod文件夹内。(如果出现 The sandbox is not sync with the podfile.lock这种错误,则表示manifest.lock和podfile.lock文件不一致),此时一般需要重新运行pod install命令。
- 配置原有的project文件(add build phase)
- 添加了
Embed Pods Frameworks
- 添加了
Copy Pod Resources
其中,pre-install hook和post-install hook可以理解成回调函数,是在podfile里对于install之前或者之后(生成工程但是还没写入磁盘)可以执行的逻辑,逻辑为:
pre_install do |installer|
# 做一些安装之前的hook
end
post_install do |installer|
# 做一些安装之后的hook
end
注意:pod install
优先遵循 Podfile 里指定的版本信息,其次遵循 Podfile.lock 里指定的版本信息来安装对应的依赖库。
Xcode工程有什么变化
在cocoaPods和Xcode工程进行集成的过程中,会有有以下流程:
- 创建workspace
创建xcworkspace文件。其实xcworkspace文件本质上只是xcodeproject的集合,数据结构如下:
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "group:Demo/Demo.xcodeproj">
</FileRef>
<FileRef
location = "group:Pods/Pods.xcodeproj">
</FileRef>
</Workspace>
- create group
在工程中创建group文件夹,逻辑上隔离一些文件 - create pod project & add pod library
创建pod.xcodeproject工程,并且将在podfile中定义的第三方库引入到这个工程之中。 -
add embed frameworks script phase
添加了[CP] Embed Pods Frameworks,相应的,多了pods_xxx的group,下列xxx.framework.sh,来完成将内部第三方库打包成.a静态库文件(在Podfile中如果选择了use_frameworks!,则此步骤会打包成.framework)
[CP] Embed Pods Frameworks
[CP] Embed Pods Frameworks
- remove embed frameworks script phase
如果本次podfile删除了部分第三方库,则此步骤会删除掉不需要的第三方库,将其的引用关系从Pod.xcodeproject工程中拿走。 -
add copy resource script phase
如果第三方库存在资源bundle,则此步骤会将资源文件进行复制到集中的目录中,方便统一进行打包和封装。相应的,会添加[CP] Copy Pods Resources脚本。
[CP] Copy Pods Resources - add check manifest.lock script phase
前文提到过,manifest.lock其实是podfile.lock的副本。此步骤会进行diff,如果存在不一致,则会提示著名的那句The sandbox is not sync with the podfile.lock错误。 - add user script phase
此步骤是对原有project工程文件进行改造。在运行过pod install后,再次打开原有工程会发现无法编译通过,因为已经做了改动。 -
首先,添加了对Pod工程的依赖,具体为引用中多了libPods_xxx.a文件。此步骤的.a文件(或者.framework文件)为上述步骤中xxx.framework.sh打包出来的文件,也就是说,cocoaPods会把所有第三方的组件封装为一个.a文件(或者.framework文件)!
静态文件引入
*建立了Pods的group,内含pods-xxx-debug.xconfig和pods-xxx.release.xconfig文件。这两个文件是对应工程的build phase的配置。相应的,主工程的Iinfo->Configurations的debug和release配置会对应上述两个配置文件。
Configurations - 上述两个配置都做了什么?包括:
Header_search_path,指向了Pod/Headers/public/xxx,添加了Pods文件编译后的头文件地址
Other_LDFLAGS,添加了-ObjC等等
一些Pods变了,例如Pods_BUILD_DIR等
至此,原有xcode工程和新建的Pod工程完成了集成和融合。