一、版本管理工具及 Ruby 工具链环境
1 背景知识
1.1 Version Control System (VCS)
版本控制系统(VCS)
是敏捷开发的重要一环
Source Code Manager
(SCM) 源码管理就属于 VCS
在SCM中有CocoaPods
和Git
等工具。CocoaPods
是针对各种语言所提供的 Package Manger (PM)
。
Git
或 SVN
是针对项目的单个文件的进行版本控制,而 PM 则是以每个独立的 Package 作为最小的管理单元。
被 PM 接管的依赖库的文件,通常会在 Git
的 .ignore
文件中选择忽略它们。
1.2 Git Submodule
Git Submodules
可以算是 PM 的“青春版”,它将单独的 git 仓库以子目录的形式嵌入在工作目录中。
它不具备 PM 工具所特有的语义化版本管理、无法处理依赖共享与冲突等。只能保存每个依赖仓库的文件状态。
Git submodule 是依赖 .gitmodules
文件来记录子模块的。
.gitmodules
仅记录了 path 和 url 以及模块名称的基本信息, 但是我们还需要记录每个 Submodule Repo 的 commit 信息,而这 commit 信息是记录在 .git/modules
目录下。同时被添加到 .gitmodules
中的 path 也会被 git 直接 ignore 掉。
1.3 Package Manger
PM 基本都具备了语义化的版本检查能力,依赖递归查找,依赖冲突解决,以及针对具体依赖的构建能力和二进制包等。
Key File | Git submodule | CocoaPods | SPM | npm |
---|---|---|---|---|
描述文件 | .gitmodules | Podfile | Package.swift | Package.json |
锁存文件 | .git/modules | Podfile.lock | Package.resolved | package-lock.json |
- 描述文件:声明了项目中存在哪些依赖,版本限制;
- 锁存文件(Lock 文件):记录了依赖包最后一次更新时的全版本列表。
1.4 CocoaPods
CocoaPods
是开发 iOS/macOS 应用程序的一个第三方库的依赖管理工具。
利用 CocoaPods
,可以定义自己的依赖关系(简称 Pods
)
Podfile
Podfile
是一个文件,以 DSL(其实直接用了 Ruby 的语法)来描述依赖关系,用于定义项目所需要使用的第三方库。
该文件支持高度定制。
Podfile.lock
这是 CocoaPods
创建的最重要的文件之一。
它记录了需要被安装的 Pod 的每个已安装的版本。
如果你想知道已安装的 Pod
是哪个版本,可以查看这个文件。
推荐将 Podfile.lock
文件加入到版本控制中,这有助于整个团队的一致性。
Manifest.lock
这是每次运行 pod install
命令时创建的 Podfile.lock
文件的副本。
如果你遇见过这样的错误 沙盒文件与 Podfile.lock
文件不同步 (The sandbox is not in sync with the Podfile.lock
),这是因为 Manifest.lock
文件和 Podfile.lock
文件不一致所引起。由于 Pods
所在的目录并不总在版本控制之下,这样可以保证开发者运行 App 之前都能更新他们的 Pods
,否则 App 可能会 crash,或者在一些不太明显的地方编译失败。
Master Specs Repo
CocoaPods
通过官方的 Spec 仓库来管理这些注册的依赖库。随着不断新增的依赖库导致 Spec 的更新和维护成为了使用者的包袱。
好在这个问题在 1.7.2 版本中已经解决了,CocoaPods
提供了 Mater Repo CDN ,可以直接 CDN 到对应的 Pod 地址而无需在通过本地的 Spec 仓库了。
同时在 1.8 版本中,官方默认的 Spec 仓库已替换为 CDN,其地址为 https://cdn.cocoapods.org。
2 Ruby 生态及工具链
CocoaPods
是通过 Ruby 语言实现的。它本身就是一个 Gem
包。
RVM
和 rbenv
都是管理多个 Ruby 环境的工具,它们都能提供不同版本的 Ruby 环境管理和切换。
2.1 RubyGems
RubyGems 是 Ruby 的一个包管理工具,这里面管理着用 Ruby 编写的工具或依赖我们称之为 Gem。
当我们使用 gem install xxx
时,会通过 rubygems.org
来查询对应的 Gem Package。
而 iOS 日常中的很多工具都是 Gem 提供的,例:Bundler
,fastlane
,jazzy
,CocoaPods
等。
在默认情况下 Gems 总是下载 library 的最新版本,这无法确保所安装的 library 版本符合我们预期。因此我们还缺一个工具。
2.2 Bundler
Gemfile 的 DSL 写法和 Podfile 如出一辙。
Bundler 是管理 Gem 依赖的工具,可以隔离不同项目中 Gem 的版本和依赖环境的差异,也是一个 Gem。
Bundler 通过读取项目中的依赖描述文件 Gemfile
,来确定各个 Gems 的版本号或者范围,来提供了稳定的应用环境。
当我们使用 bundle install
它会生成 Gemfile.lock
将当前 librarys 使用的具体版本号写入其中。之后,他人再通过 bundle install
来安装 libaray 时则会读取 Gemfile.lock
中的 librarys、版本信息等。
Gemfile
Bundler 依据项目中的 Gemfile
文件来管理 Gem,(而 CocoaPods
通过 Podfile 来管理 Pod)。
那什么情况会用到 Gemfile 呢 ?
CocoaPods
每年都会有一些重大版本的升级,前面聊到过 CocoaPods
在 install
过程中会对项目的 .xcodeproj
文件进行修改,不同版本其有所不同,这些在变更都可能导致大量 conflicts
,处理不好,项目就不能正常运行了。我想你一定不愿意去修改 .xcodeproj
的冲突。
如果项目是基于 fastlane
来进行持续集成的相关工作以及 App 的打包工作等,也需要其版本管理等功能。
3 如何安装一套可管控的 Ruby 工具链?
我们可以使用 homebrew
+ rbenv
+ RubyGems
+ Bundler
这一整套工具链来控制一个工程中 Ruby 工具的版本依赖。
3.1 使用 homebrew
安装 rbenv
1 | brew install rbenv |
安装成功后输入 rbenv
就可以看到相关提示
3.2 使用 rbenv
管理 Ruby 版本
1 | rbenv install 2.6.0 |
安装成功后,我们让其生效:
1 | rbenv global 2.6.0 |
rbenv global 2.6.0 # 默认使用 2.6.0
rbenv shell 2.6.0 # 当前的 shell 使用 2.6.0, 会设置一个 RBENV_VERSION
环境变量
rbenv local j2.6.0 # 当前目录使用2.6.0, 会生成一个 .rbenv-version
文件
输入上述命令后,可能会有报错。
rbenv
提示我们在.zshrc
中增加一行eval "$(rbenv init -)"
语句来对rbenv
环境进行初始化。如果报错,我们增加并重启终端即可。
1 | $ ruby --version |
3.3 查询系统级 Gem
依赖
1 | gem list |
4 如何使用 Bundler 管理工程中的 Gem 环境
在项目中增加一个 Gemfile
描述,从而锁定当前项目中的 Gem
依赖环境。
4.1 在 iOS 工程中初始化 Bundler
环境
初始化一个 Bundler
环境(其实就是自动创建一个 Gemfile
文件):
1 | bundle init |
4.2 在 Gemfile
中声明使用的 CocoaPods
版本并安装
编辑 Gemfile
文件,之后执行一下 bundle install
:
1 | bundle install |
4.3 使用当前环境下的 CocoaPods
版本操作 iOS 工程
检查一下当前 Bundler
环境下的 Gem
列表:
1 | bundle exec gem list |
此时我们使用 bundle exec pod install
来执行 Install 这个操作,就可以使用 CocoaPods 1.5.3
版本来执行 Pod
操作了(前提是你还需要写一个 Podfile
)。
1 | bundle exec pod install |