Cocoapods
Cocoapods 是iOS开发最常用的一个老牌包管理工具,类似npm,maven。
Cocoapods官网是这样介绍自己的
CocoaPods is a dependency manager for Swift and Objective-C Cocoa projects. It has over 83 thousand libraries and is used in over 3 million apps. CocoaPods can help you scale your projects elegantly.
它已经涵盖了8.3w个三方库,超过300w app在使用它。
下载
sudo gem install cocoapods
Cocoapods是ruby编写的,依赖于ruby环境,需要用到ruby的包管理工具rubygems
这里的下载命令用到sudo,是因为rubygems的默认安装目录/Library/Ruby/Gems/或者rvm默认安装目录~/.rvm/gems需要root权限,可参考rubygems安装目录
开始使用
首先我们创建一个新项目 TestCocoapods
Cocoapods提供了快捷命令pod init
,用来创建Podfile文件
我们在Podfile文件中加上几个组件
platform :ios, '10.0'
target 'TestCocoapods' do
pod 'AFNetworking'
pod 'Masonry'
end
做完上面的准备工作,然后再执行一下 pod install 或者 pod update 命令就可以运行项目了.那么问题来了,pod install 或者 pod update 有啥区别呢?
pod install 和 pod update 到底有什么不同呢?
Answer:
官方文档pod install vs. pod update是这样说的:
Use pod install to install new pods in your project. Even if you already have a Podfile and ran pod install before; so even if you are just adding/removing pods to a project already using CocoaPods.
Use pod update [PODNAME] only when you want to update pods to a newer version.
官方建议只有在更新pod版本的时候才使用pod update,其他的情况都应该使用pod install
对pod install 的描述
Every time the pod install command is run — and downloads and install new pods — it writes the version it has installed, for each pods, in the Podfile.lock file. This file keeps track of the installed version of each pod and locks those versions.
When you run pod install, it only resolves dependencies for pods that are not already listed in the Podfile.lock.
For pods listed in the Podfile.lock, it downloads the explicit version listed in the Podfile.lock without trying to check if a newer version is available
For pods not listed in the Podfile.lock yet, it searches for the version that matches what is described in the Podfile (like in pod 'MyPod', '~>1.2')
pod install 会根据Podfile.lock文件所依赖的版本号进行下载,不会去检查是否有新版本存在,也不会更新仓库
对pod update 的描述
When you run pod update PODNAME, CocoaPods will try to find an updated version of the pod PODNAME, without taking into account the version listed in Podfile.lock. It will update the pod to the latest version possible (as long as it matches the version restrictions in your Podfile).
If you run pod update with no pod name, CocoaPods will update every pod listed in your Podfile to the latest version possible.
pod update 会忽略Podfile.lock文件,而去更新仓库的最新版本,符合Podfile所规定的版本,比如Podfile的依赖是这样的 ~> 1.2,如果仓库的最新版本是1.3版本,他就会更新到1.3,如果是2.x,则不会更新,版本依赖符号含义,可参考下方版本号控制
下面我们通过阅读Cocoapods的源码来了解一下这些不同,再看看还有那些不同是官网描述没有提到的。
分析
在看源码之前我们要先了解一下,Cocoapods不止是Cocoapods这一个仓库,而是拆分成了多个仓库,具体的项目可以查看Cocoapods-github的ReadMe-Projects ,还有一些官方的插件,可通过pod plugins installed命令查看。完整的依赖链可以查看Cocoapods-Master下的Gemfile文件。
我们今天阅读源码要涉及到的项目有下面几个,我们在下载Cocoapods的时候,这些项目也都被下载到gems目录下了
xcodeproj
解析整个Xcode工程,功能很强大,主要用来创建target,添加文件,添加Build Phases下的脚本等。
cocoapods-core
Cocoapods的实现库,包括spec和podfile。
claide
封装了命令行接口,自己写Ruby命令行工具也可以用这个库
Manifest.lock
Manifest.lock就是Podfile.lock的备份
- 写入文件的方法会判断当前的lock文件和之前的lock文件是否相同,如果不相同则重写
- install在podfile文件有增减pod的时候会触发重写
- update在podfile文件有增减pod或者pod版本号变更的时候会重写
- 所以如果podfile文件没有任何变更,不管是install还是update都不会重写Podfile.lock文件和Manifest.lock文件
- Podfile.lock 和 Manifest.lock是同时写入的,Manifest.lock就是Podfile.lock的备份
- Podfile.lock文件在项目根目录下 TestCocoapods/Podfile.lock
- Manifest.lock文件在Pods目录下 TestCocoapods/Pods/Manifest.lock
- 在build项目时,如果两个文件不一致,会报错 The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.
- 这种错一般是你pull了别人的Podfile.lock文件,而别人的Podfile.lock文件变更了,导致和你本地的Manifest.lock不一致,这个时候就需要install或者update一下重写这两个文件
- 比对脚本在Xcode的Build Phases下,每次install或者update的时候都会写入一个名为[CP] Check Pods Manifest.lock的Run Script Phase脚本
- 写入方法在cocoapods/installer/user_project_integrator/target_integrator.rb/add_check_manifest_lock_script_phase中,如果想要用工具在Xcode中写入脚本,可以参考这个方法
总结
install的执行步骤
:先解析podfile中的版本号,如果podfile中指定了版本号,则去本地仓库中找指定的版本号,如果没有找到对应版本号的内容,则报错。若podfile没有指定版本号,则会去podfile.lock中寻找版本号,如果是新增的库的话会去本地找该库最新的版本,如果找不到也报错。若podfile中可以找到版本号,则根据lock中的版本号去本地仓库找对应的版本号。若找不到也报错。上述步骤一旦能找到相应版本的库,则Copy到工程根目录的Pods文件下。
update的执行步骤
:先git pull远端仓库,多个source的话要更新多个仓库,如果没有科学上网的话,要更新github上的官方仓库就得看命了。当然现在增加了CDN节点之后提高了分发和下载速度,不过还是不能解决因为不能科学上网而更新慢的问题。更新完仓库后,回去解析podfile中的版本号,如果指定了版本号,就去本地仓库中找指定的版本号,如果没找到,则报错。若podfile没有指定版本,则会直接去本地仓库找最新版本,若没找到,则报错。上述步骤一旦能找到相应版本的库,则Copy到工程根目录的Pods文件下。
所以若是不涉及版本更新
的话,用install
就够了!
备注
版本号控制
~> x.y.z 是指 >= x.y.z, <x.(y+1).z 的版本
~> x.y 是指 >= x.y, <(x+1).0 的版本
1. pod "AFNetworking" # 不指定依赖库版本,依赖最新版本
2. pod "AFNetworking", "2.0" # 使用 = 2.0 的版本
3. pod "AFNetworking", "> 2.0" # 使用 > 2.0 的版本
4. pod "AFNetworking", ">= 2.0" # 使用 >= 2.0 的版本
5. pod "AFNetworking", "< 2.0" # 使用 < 2.0 的版本
6. pod "AFNetworking", "<= 2.0" # 使用 <= 2.0 的版本
7. pod "AFNetworking", '>= 2.0', '< 4.0 # 使用 >= 2.0,< 4.0 的版本
8. pod "AFNetworking", "~> 0.1.2" # 使用 >= 0.1.2 , < 0.2 的版本
9. pod "AFNetworking", "~> 0.1" # 使用 >= 0.1 , < 1.0 的版本
10. pod "AFNetworking", "~> 0" # > 0 的版本,这个和1是一个效果
在组件化的项目工程中,一般是要写死组件版本号
,否则会造成组内某些人版本号不一致而引发一系列问题。