本文作者:Edmond
CocoaPods 历险记这个专题是 Edmond 和 冬瓜 共同撰写,对于 iOS / macOS 工程中版本管理工具 CocoaPods 的实现细节、原理、源码、实践与经验的分享记录,旨在帮助大家能够更加了解这个依赖管理工具,而不仅局限于
pod install
和pod update
。
本文知识目录
引子
在上文 版本管理工具及 Ruby 工具链环境 中,我们聊到如何统一管理团队小伙伴的 CocoaPods 生产环境及使用到的 Ruby 工具链。今天让我们将目光转到 CocoaPods 身上,一起来聊聊它的主要构成,以及各个组件在整个 Pods 工作流的关系。
为了整体把握 CocoaPods 这个项目,建议大家去入门一下 Ruby 这门脚本语言。另外本文基于 CocoaPods 1.9.2 版本。
CocoaPods 的核心组件
作为包管理工具,CocoaPods 随着 Apple 生态的蓬勃发展也在不断迭代和进化,并且各部分核心功能也都演化出相对独立的组件。这些功能独立的组件,均拆分出一个个独立的 Gem 包,而 CocoaPods 则是这些组件的“集大成者”。
CocoaPods 依赖总览
我们知道在 Pod 管理的项目中,Podfile
文件里描述了它所依赖的 dependencies,类似的 Gem 的依赖可以在 Gemfile
中查看。那 CocoaPods 的 Gemfile
有哪些依赖呢?
SKIP_UNRELEASED_VERSIONS = false
# ...
source 'https://rubygems.org'
gemspec
gem 'json', :git => 'https://github.com/segiddins/json.git', :branch => 'seg-1.7.7-ruby-2.2'
group :development do
cp_gem 'claide', 'CLAide'
cp_gem 'cocoapods-core', 'Core', '1-9-stable'
cp_gem 'cocoapods-deintegrate', 'cocoapods-deintegrate'
cp_gem 'cocoapods-downloader', 'cocoapods-downloader'
cp_gem 'cocoapods-plugins', 'cocoapods-plugins'
cp_gem 'cocoapods-search', 'cocoapods-search'
cp_gem 'cocoapods-stats', 'cocoapods-stats'
cp_gem 'cocoapods-trunk', 'cocoapods-trunk'
cp_gem 'cocoapods-try', 'cocoapods-try'
cp_gem 'molinillo', 'Molinillo'
cp_gem 'nanaimo', 'Nanaimo'
cp_gem 'xcodeproj', 'Xcodeproj'
gem 'cocoapods-dependencies', '~> 1.0.beta.1'
# ...
# Integration tests
gem 'diffy'
gem 'clintegracon'
# Code Quality
gem 'inch_by_inch'
gem 'rubocop'
gem 'danger'
end
group :debugging do
gem 'cocoapods_debug'
gem 'rb-fsevent'
gem 'kicker'
gem 'awesome_print'
gem 'ruby-prof', :platforms => [:ruby]
end
上面的 Gemfile
中我们看到很多通过 cp_gem
装载的 Gem 库,其方法如下:
def cp_gem(name, repo_name, branch = 'master', path: false)
return gem name if SKIP_UNRELEASED_VERSIONS
opts = if path
{ :path => "../#{repo_name}" }
else
url = "https://github.com/CocoaPods/#{repo_name}.git"
{ :git => url, :branch => branch }
end
gem name, opts
end
它是用于方便开发和调试,当 SKIP_UNRELEASED_VERSIONS
为 false && path
为 true
时会使用与本地的 CocoaPods 项目同级目录下的 git 仓库,否则会使用对应的项目直接通过 Gem 加载。
通过简单的目录分割和 Gemfile
管理,就实现了最基本又最直观的热插拔,对组件开发十分友好。所以你只要将多个仓库如下图方式排列,即可实现跨仓库组件开发:
$ ls -l
lrwxr-xr-x 1 gua staff 31 Jul 30 21:34 CocoaPods
lrwxr-xr-x 1 gua staff 26 Jul 31 13:27 Core
lrwxr-xr-x 1 gua staff 31 Jul 31 10:14 Molinillo
lrwxr-xr-x 1 gua staff 31 Aug 15 11:32 Xcodeproj
lrwxr-xr-x 1 gua staff 42 Jul 31 10:14 cocoapods-downloader
组件构成和对应职责
通过上面对于 Gemfile
的简单分析,可以看出 CocoaPods 不仅仅是一个仓库那么简单,它作为一个三方库版本管理工具,对自身组件的管理和组件化也是十分讲究的。我们继续来看这份 Gemfile
中的核心开发组件:
CLAide
The CLAide gem is a simple command line parser, which provides an API that allows you to quickly create a full featured command-line interface.
CLAide[2] 虽然是一个简单的命令行解释器,但它提供了功能齐全的命令行界面和 API。它不仅负责解析我们使用到的 Pods
命令,如:pod install
, pod update
等,还可用于封装常用的一些脚本,将其打包成简单的命令行小工具。
PS: 所谓命令行解释器就是从标准输入或者文件中读取命令并执行的程序。详见 Wiki[3]。
cocoapods-core
The CocoaPods-Core gem provides support to work with the models of CocoaPods, for example the Podspecs or the Podfile.
CocoaPods-Core[4] 用于 CocoaPods 中模板文件的解析,包括 Podfile
、.podspec
,以及所有的 .lock
文件中特殊的 YAML 文件。
cocoapods-downloader
The Cocoapods-downloader gem is a small library that provides downloaders for various source control types (HTTP/SVN/Git/Mercurial). It can deal with tags, c