前言
本文描述 Cocoapods 的工作原理和源码分析,阅读完本文后可以更好的理解在使用 Cocoapods 中遇到的问题并找到解决方法,并且有新的开发语言出现时也可以开发一款自己的包管理工具。
Cocoapods 的安装
Cocoapods 的安装非常简单,只需一行命令即可(需对系统的网络请求进行翻墙)
$ sudo gem install cocoapods
安装完后可在终端输入 pod ,会有如下输出:
pod.png显示了 pod 的所有可用的命令和命令选项。
Cocoapods 的使用
打开终端,切换到你的工程目录,输入下面的命令
pod init
终端输入 ls 可以看到已经多了个 Podfile 文件,使用 vi 打开,内容如下
# Uncomment the next line to define a global platform for your project
# platform :ios, '9.0'
target 'SwiftDemo' do
# Comment the next line if you're not using Swift and don't want to use dynamic frameworks
use_frameworks!
# Pods for SwiftDemo
target 'SwiftDemoTests' do
inherit! :search_paths
# Pods for testing
end
target 'SwiftDemoUITests' do
inherit! :search_paths
# Pods for testing
end
end
编写好 Podfile 后执行以下命令:
pod install
Cocoapods 的工作流程
pod install 执行流程可分为如下五个步骤
- 查看 ~/.cocoapods/repo/master/Specs 是否存在
- 存在,从这个本地三方库信息库中获取 Podfile 中对应三方库的 git 地址
- 不存在,输出 Setting up CocoaPods Master repo,并拉取到 ~/.cocoapods/repo/中
- 使用 git 命令从 GitHub 上拉取 Podfile 中对应的三方库源码
在终端中输入如下命令
cd ~/.cocoapods/repo/master/Specs
ls
repos.png
可以看到很多文件夹,其中就包含我们平常使用的三方库的文件夹。
随便选进入一个文件夹,这里我 cd 进了 Alamofire 文件夹。
这里全是 Alamofire 的 release 版本号,当我们使用 pod search Alamofire 命令时会将这里的所有版本号输出出来。
cd 进最新版本的文件夹中,里面是一个 Alamofire.podspec.json 文件,使用 vi 打开,内容如下
{
"name": "Alamofire",
"version": "4.0.0",
"license": "MIT",
"summary": "Elegant HTTP Networking in Swift",
"homepage":
"social_media_url":
"authors": {
"Alamofire Software Foundation": "info@alamofire.org"
},
"source": {
"git":
"tag": "4.0.0"
},
"platforms": {
"ios": "8.0",
"osx": "10.9",
"tvos": "9.0",
"watchos": "2.0"
},
"source_files": "Source/*.swift"
}
可以看到这里包含了所有的三方库的相关信息,包括名字,协议,描述,Github 地址,支持平台等。
在查找到对应文件夹后,进行 json 数据解析,获得三方库的 repo 地址,调用本地 git 命令拉取源码,拉取完成后调用本地 xcodebuild 命令把三方库编译为 Framework。
源码分析
commands.png其中 setup 命令用于第一次使用 cocoapods 时对使用环境进行设置,下面对 setup 命令的源码进行分析。
require 'fileutils'
module Pod
class Command
class Setup < Command
self.summary = 'Setup the CocoaPods environment'
self.description = <<-DESC
Creates a directory at `~/.cocoapods/repos` which will hold your spec-repos.
This is where it will create a clone of the public `master` spec-repo from:
If the clone already exists, it will ensure that it is up-to-date.
DESC
extend Executable
executable :git
def run
UI.section 'Setting up CocoaPods master repo' do
if master_repo_dir.exist?
set_master_repo_url
set_master_repo_branch
update_master_repo
else
add_master_repo
end
end
UI.puts 'Setup completed'.green
end
#--------------------------------------#
# @!group Setup steps
# Sets the url of the master repo according to whether it is push.
#
# @return [void]
#
def set_master_repo_url
Dir.chdir(master_repo_dir) do
git('remote', 'set-url', 'origin', url)
end
end
# Adds the master repo from the remote.
#
# @return [void]
#
def add_master_repo
cmd = ['master', url, 'master']
Repo::Add.parse(cmd).run
end
# Updates the master repo against the remote.
#
# @return [void]
#
def update_master_repo
show_output = !config.silent?
config.sources_manager.update('master', show_output)
end
# Sets the repo to the master branch.
#
# @note This is not needed anymore as it was used for CocoaPods 0.6
# release candidates.
#
# @return [void]
#
def set_master_repo_branch
Dir.chdir(master_repo_dir) do
git %w(checkout master)
end
end
#--------------------------------------#
# @!group Private helpers
# @return [String] the url to use according to whether push mode should
# be enabled.
#
def url
self.class.read_only_url
end
# @return [String] the read only url of the master repo.
#
def self.read_only_url
end
# @return [Pathname] the directory of the master repo.
#
def master_repo_dir
config.sources_manager.master_repo_dir
end
end
end
end
其执行流程可分为如下步骤
- 判断 ~/.cocoapods/repo目录是否存在
- 存在,依次调用 set_master_repo_url,set_master_repo_branch,update_master_repo 三个函数分别设置 repo 主分支地址,git checkout 到主分支,拉取主分支代码,更新repo
- 不存在,添加主分支 repo
使用 Cocoapods 的小技巧
大家在使用 pod install 命令时一般会加上 --no-repo-update 选项。这使得 pod install 不进行本地三方库信息库 git pull 的更新操作。若 Podfile 中指定 Alamofire 的版本号为 4.2.0,但本地 ~/cocoapods/repo/master/Specs/Alamofire 中并没有此版本号,此时使用 pod install --no-repo-update 会出现如下错误,
pod install.png若直接使用 pod install 便会先执行 pod repo update,由于 github 需要翻墙,并且更新的内容过大就会等待很久。
既然知道了 Cocoapods 的原理,我们便可以手动在 ~./cocoapods/repo/master/Specs 中添加我们需要的三方库版本信息,避免了把所有的并没有使用到的三方库信息更新到本地。
下面以添加 Alamofire 4.2.0 版本信息到本地为例子。
在终端输入如下命令
cd ~/.cocoapods/repo/master/Specs/Alamofire/
mkdir 4.2.0
cp ~/.cocoapods/repo/master/Specs/Alamofire/1.1.3/Alamofire.podspec.json ./4.2.0
上面的命令创建了名为 4.2.0 的文件夹,并复制了一个库信息的 json 文件到新创建的文件夹中,用 vi 打开该文件,内容如下
{
"name": "Alamofire",
"version": "1.1.3",
"license": "MIT",
"summary": "Elegant HTTP Networking in Swift",
"homepage":
"social_media_url":
"authors": {
"Mattt Thompson": "m@mattt.me"
},
"source": {
"git":
"tag": "1.1.3"
},
"platforms": {
"ios": "8.0"
},
"source_files": "Source/*.swift",
"requires_arc": true
}
我们需要修改版本号,source 的 tag。那 source 的 tag 怎么知道是多少呢,这个可以从 GitHub 上找到。
release version.png可以看到所有 release 版本信息。
总结
到此,你已经知道了 Cocoapods 是调用了本地的 git 命令来实现拉取源码。当出现一门新的语言,可以按照类似逻辑开发自己的三方库管理工具。