作者:xiaobo
最近需要把 iOS 工程的 pod 库二进制化,但发现这方面的资料相对比较少;甚至一些介绍 cocoapods 的文章,也很少从宏观上梳理 cocoapods 的工作流程;大都是关于 pod 指令,以及如何安装使用的文章。
但指令只是达到目的工具而已,我觉得需要先把思路捋清楚,所以尝试简单直白的描述下 cocoapods 的工作流程。
Cocoapods 是什么
抛开平台差异,cocoapods 就是个包管理软件,它和 homebrew,npm,等包管理软件类似,区别就是它管理的是 iOS 开发中, Xcode 工程的软件包;
和其他包管理软件类似,cocoapods 也有它的核心终端指令:pod
;执行包的安装通过: pod install
。
工作流程
cocoapods 的运行原理,其实很简单,它依赖三个核心概念:
1、Podfile 文件,用来写清楚需要安装哪些 pod 库。
2、Specs 中央仓库,托管在 github 上的文件仓库。类似一个 “路由表”,用来查询某个 pod 库的详细信息。specs 也常被称为“源”,或者“specs 源”。
3、podspec 描述文件,安装某个 pod 库所需的详细信息,主要的几项包括:代码地址、作者、版本、以及代码文件是哪些…等等。
作为库的使用方,我们最常见的就是 Podfile 文件;如果库是的提供方,就需要编写 podspec,同时把写好的 podspec 提交到 specs 重要仓库。下图是它们三者的关系:
使用方: Podfile 文件
Podfile 文件描述了工程需要引入哪些的 pod 库,一般写法如下:
# CocoaPods Source
source 'https://github.com/CocoaPods/Specs.git'
#..其他部分..
pod 'Alamofire', '1.1.0',
pod 'WebViewBridge', '1.0.0'
#..其他部分..
上边是我们经常写的 Podfile 文件格式,需要说明两点:
1、source 'https://github.com/CocoaPods/Specs.git'
source 函数,用来告诉 cocoapods 去哪个 Specs 仓库中查询 pod 库,大部分情况下是 cocoapods 官方的 specs 仓库,也就是上边写的 git 地址。
如果有需要,可以自己创建一个 specs 仓库,同时也可以写多个 source 源,cocoapods 会依次查询:
source ‘https://github.com/CocoaPods/Specs.git’
source ‘https://git.mywebsite.com/demo1.git’
source ‘https://git.mywebsite.com/demo12.git’
2、pod 'Alamofire', '1.1.0'
这是我们常用的 pod 库的引入方式:通过版本号引入;这种方式下,当执行 pod install
的时候,cocoapods 就会在 Specs 仓库中去查找对应版本,然后根据该版本下的 podspec
描述去安装 (安装之前,会先计算依赖)。
你可以通过下来三个简单的指令来查看 pod 命令的具体内容:
1、找到 pod 命令的具体路径
$ type pod
pod is /Users/zhangsan/.rvm/gems/ruby-2.6.3/bin/pod
2、查看它的文件类型
$ file /Users/zhangsan/.rvm/gems/ruby-2.6.3/bin/pod
/Users/zhangsan/.rvm/gems/ruby-2.6.3/bin/pod: Ruby script text executable, ASCII text
3、浏览 pod 命令的具体代码
$ cat /Users/zhangsan/.rvm/gems/ruby-2.6.3/bin/pod
... 内容省略 ...
所以 pod 是个 ruby 的可执行脚本,你可以简单理解为一个 ruby 函数,仓库名是它的第一参数,版本号是第二参数(不写版本号,默认引入最新版本);
除了例子中版本号引入 pod 的方式,pod 还支持其他方式引入:
1、自己指定 git 仓库,以及 branch 或者 tag:
pod ‘Alamofire’, :git => ‘https://github.com/Alamofire/Alamofire.git’, :branch => ‘dev’
或者 tag
pod ‘Alamofire’, :git => ‘https://github.com/Alamofire/Alamofire.git’, :tag => ‘1.0.0’
2、还可以指向本地 path,:path
这种方式经常用在开发调试中:
pod ‘demoPod’,
:path
=> ‘/Users/zhangsan/….’这种方式下,pod 会自动查找该目录下的 podspec 文件进行安装。
3、或者,用最直接的方式,指定 :podspec
,使用这种方式,podspec 文件路径可以是本地 (file 资源),也可以是一个 http 资源:
pod ‘demoPod’,
:podspec
=> ‘/Users/zhangsan/…’或者使用 http 的方式
pod ‘demoPod’,
:podspec
=> ‘https://gitlab.some.com/whose/demopod/raw/master/demopod.podspec’注意:http 的方式下,该 http 服务必须是一个文件下载服务!
上边通过 :branch
,:tag
,:path
, :podsepc
传递参数时候,都需要在最前边加 :
,这其实是 ruby 语法中 Hash 的 key
,也就是常说的字典的 key
, =>
后边的值是 value
,pod 函数会把所有用 :
开始传递的 key value 存入到一个 hash 中。
Specs 源
前边提到,cocoapods 官方的 specs 源(或者叫 specs repo),本质就是托管在 github 上的一个 git 仓库。里边记录了非常多的 pod 库的 podspec 信息。点击去 github 查看。
1、实际开发中,我们可以添加私有的 specs repo,而不去直接使用上边提到的 cocoapods 官方的 specs repo。这也是比较推荐的一种方式,原因是官方 specs 越来越大,而实际我们只用到了其中的一小部分。直接 source 它,会严重拖慢 pod install 的时间;建立私有的 specs repo 也是加速 pod update/install 最有效的方式。使用下边的命令可以快速的自建 specs repo :
$ pod repo add REPO_NAME SOURCE_URL
2、第一次执行 pod install/update/search/outdated ,会先把所有用到的远端 specs repos 拉取到本地,使用下边命令可以查看本地所有的 specs 源仓库:
$ l ~/.cocoapods/repos
库提供方:podspec 描述文件
当我们需要把一个自己的代码库提供给别人使用时,就需要编写 .podspec 描述文件,下边是开源三方库 WebViewJavascriptBridge 的 podspec:
Pod::Spec.new do |s|
s.name = 'WebViewJavascriptBridge'
s.version = '6.0.3'
s.summary = 'An iOS & OSX bridge for sending messages between Obj-C/Swift and JavaScript in WKWebViews, UIWebViews & WebViews.'
s.homepage = 'https://github.com/marcuswestin/WebViewJavascriptBridge'
...省略部分...
s.ios.source_files = 'WebViewJavascriptBridge/*.{h,m}'
...省略部分...
end
上边我们可以看到一些关于这个库的引入信息:版本号、homepage、源码文件有哪些等。
1、使用 ruby 解析 podspec
上边的第一行内容:
Pod::Spec.new do |s|
表示,该文件里边描述的是一个 spec 对象 s。该对象定义在 Pod
module 下,这种写法是 ruby 的语法。我们使用下边的 ruby 脚本,可以把这个文件的对象解析出来:
// 导入 cocoapods 核心库文件
require 'cocoapods-core'
spec_obj = Pod::Specification.from_file(podspec_path)
podspec_path
是 podspec 文件的本地路径;解析后,我们就可以直接访问 spec_obj 中的所有属性:
spec_obj.name (仓库名)
spec_obj.version (版本号)
spec_obj.attributes_hash (得到所有信息的 hash 字典)
Specification
这个类的具体使用,可以查看 cocoapods 的官方 API,访问该网站需要一些“上网常识”。
2、使用 pod 命令生成标准的 podspec 文件
一般,我们需要通过 pod 提供的标准命令来生成这个 podspec 文件:
pod spec create [NAME | https://github.com/USER/REPO]
支持本地命名,或者一个通过一个远程仓库
3、提交 podspec 到 specs 中
写好 podspec 后,我们需要把这个文件提交到 specs 中,由于 specs 是一个 git 仓库,所以我们完全可以通过 git 命令提交。但这并不是 cocoapods 推荐的做法,建议使用 cocoapods 的命令:
pod repo push artsy-specs ~/Desktop/Artsy+OSSUIFonts.podspec –allow-warngins
上边 artsy-specs 是 specs 仓库名。使用这种方式,cocoapods 会进行一次 lint 检查,来避免 podspec 文件书写格式出错,--allow-warngins
表示忽略警告,可以不加,也建议最好不加。
使用 pod 命令总结
1、限制版本号的写法
通过版本号引入仓库的时候,有三种写法:
a: 固定版本的方式引入
pod 'demoPod', '1.1.0'
这种方式,引入时,版本固定为 1.1.0。
b: 大于或者等于版本号
pod 'demoPod', '>= 1.1.0'
这种也比较好理解,只要比 1.1.0
大或者相等的版本,都可以引入。
c: 末尾变化的方式
pod 'demoPod', '~> 1.1.0'
~>
表示的是末尾大于等于
。也就是从 1.1.0
到 1.1.99999
。 表示从 0 到无限大(理论上)。
2、Pods 文件夹
Pods/
是一个文件夹,所有已经安装的 pod 库的资源都在该文件夹下,类似 npm install
后的 node_modules
文件夹。一般该文件夹会被加到 .gitignore
中,不进行 git 提交,目的是为了节省 git 仓库的存储空间。
3、Podfile.lock 文件
这是一个 lock 文件,再每次执行过 pod install / update 后生成。该文件的内容是记录已经安装的 pod 库版本号,和版本之间的依赖问题。
PODS:
- GCDWebServer (3.5.3):
- GCDWebServer/Core (= 3.5.3)
- GCDWebServer/Core (3.5.3)
DEPENDENCIES:
- GCDWebServer (= 3.5.3)
SPEC REPOS:
https://github.com/CocoaPods/Specs.git:
- GCDWebServer
......
多人开发中,提交代码的时候,最好每次都提交该文件,这样一定程度上减少不同人的开发环境下 pod 库版本不一致的问题,特别是当 Podfile 中不是使用写死版本号的情况。
4、pod install / outdated / update
pod install
一般情况,我们都执行的是 pod install
来安装 pod 库,
首次安装: 由于没有 podfile.lock 文件,pod install 会安装满足 Podfile 文件限制条件下的最新的 pod 库。首次安装如果本地还没有 specs repo,该命令会先下载 specs repos。
非首次安装:这种情况,pod install 则会按照 podfile.lock 指定的版本进行安装,前提是 Podfile 没有发生变化。
非首次安装,且 Podfile 中 Pod 库版本发生变化:此时,pod install 需要尝试下载满足条件的最新的 pod 库,如果找到,就用新版本和 podfile.lock 文件中的版本做依赖计算,通过后,进行安装。
除了首次安装,pod install 命令永远不会更新 specs repo,所以,大部分情况,Podfile 发生变更后,我们都需要执行 pod update
。
pod update
一般 pod update 有两种用法:
$ pod update (更新全部 pod 库)
$ pod update PodName (更新执行 Pod 库)
pod update 要做的第一件事情,就是更新 specs repo。然后更新满足限制条件的最新的 pod 库。Podfile.lock 的版本限制会被忽略。
pod outdated
一般很少被用到,该命令是一条查询命令,不会对已经安装的 pod 库做任何更新。它的作用是检查已经安装的 pod 库是否有更新。它只做两件事情:
1、更新 specs repo
2、计算出哪些 pod 库发生了更新,然后输出到 terminal。
参考文档
https://guides.cocoapods.org/
(全文完)