一、前言

在iOS开发过程中,你是否常常遇到这些挑战:

每次启动新项目,都需要手动设置开发环境;有时,在安装第三方工具时需要sudo权限,这导致以后每次安装工具都需要手动输入密码,无法实现自动化。另外,每当启动新的CI服务时,都需要手动登录和配置一遍。更令人头疼的是,随着Xcode版本的更新,已经配置好的CI服务也需要重新设置。

为何会如此麻烦呢?主要是因为在项目初始阶段未能做好统一配置。

所谓统一配置,即将所有配置信息以文本格式存放在Git中。这样,我们随时可以查看修改记录,帮助我们比较不同配置之间的差异,从而不断更新迭代。

有了统一配置,任何工程师都能搭建出一模一样的开发环境,构建功能一致的App。此外,统一配置还使我们能够根据需求扩展CI服务,无需手动操作。更重要的是,统一配置还可以应用到其他类似的iOS项目中,极大地减轻了项目启动阶段的搭建成本。

二、Ruby 工具链

我们可以利用Ruby工具链为整个项目建立一致的开发和构建环境。为何选择Ruby而非其他语言呢?因为在iOS开发领域,目前流行的第三方工具CocoaPodsfastlane都是用Ruby开发的。特别值得一提的是,Ruby拥有成熟的依赖库管理工具RubyGemsBundler,后者能有效地管理CocoaPodsfastlane的版本。

这种选择带来了几个重要的优势:

  1. 生态系统的兼容性:由于CocoaPodsfastlane等主要工具是用Ruby开发的,因此使用Ruby可以确保与这些工具的生态系统兼容性,减少潜在的兼容性问题。
  2. 成熟的依赖管理工具:RubyGemsBundler是非常成熟的依赖管理工具,能够轻松地管理项目所需的各种库和工具的版本,从而确保开发环境的一致性。
  3. 易于学习和使用:Ruby语言相对简单易学,因此使用Ruby作为开发环境配置工具的语言,可以降低团队成员学习成本,提高开发效率。

总的来说,选择Ruby作为项目的开发环境配置工具语言,是基于其与iOS开发生态系统的高度集成以及Ruby本身成熟的依赖管理工具。这样可以确保项目的开发环境与流行的iOS开发工具保持一致,并提高团队的开发效率。

开发环境统一配置图

通常情况下,确保统一的开发环境应从操作系统开始。对于iOS开发而言,macOS是唯一支持的操作系统。在公司环境中,macOS的版本通常由IT部门统一管理和更新。需要注意的是,当公司更新了我们开发环境所需的macOS版本时,必须同时更新CI服务器上的macOS版本,以确保一致性。

这种关注操作系统版本一致性的做法至关重要,因为:

  1. 开发环境一致性:统一的操作系统版本可以确保团队成员在相同的开发环境中工作,避免因为版本差异而产生的问题。

  2. 支持和兼容性:iOS开发需要依赖于特定版本的Xcode和其他开发工具。确保CI服务器上的macOS版本与开发环境一致,可以保证CI过程中的兼容性和稳定性。

  3. 减少配置和调试时间:如果开发环境和CI服务器上的macOS版本不一致,可能会导致一些与操作系统相关的问题,需要花费额外的时间来调试和解决。一致的操作系统版本可以减少这种情况的发生,提高开发效率。

因此,确保开发环境和CI服务器上的macOS版本保持一致是保障团队协作和项目顺利进行的重要步骤。

三、Xcode

位于 macOS 上层的是 Xcoderbenv。其中,Xcode是iOS开发和构建的主要工具。在同一个项目中,最好使用相同版本的Xcode进行开发和构建,以确保一致性。我们可以在项目的README.md文件中注明所使用的Xcode版本。

为了保证团队成员都安装同一个版本的Xcode,要到有自动更新功能的 Mac App Store 中下载 Xcode,而是到苹果的开发者网站搜索并下载。

有时候,我们需要安装不同版本Xcode开发维护不同版本的Xcode创建的项目。所以本机有可能安装多个版本的Xcode,此时需要特别注意,为了保证所使用的编译器版本一致,在每次执行自动化命令之前(如执行bundle exec fastlane test),要先使用xcode-select -s来选择该项目所对应版本的 Xcode
比如:在开发 Test App 时,因为需要本机安装了多个App,所以每次执行自动化命令之前都会执行xcode-select -s /Applications/Xcode14.app/Contents/Developer来选择 Test App 项目所使用的 Xcode。这里的Xcode14.app就是我安装的 Xcode 14 版所在的位置。

四、rbenv

4.1安装 Ruby 版本管理工具

确保Xcode版本一致后,由于后续将使用到CocoaPods等第三方Ruby工具,因此整个项目团队必须保持一致的Ruby版本。为实现自动化安装和管理这些工具,我们需要使用Ruby环境管理工具。

目前流行的Ruby环境管理工具包括RVMrbenv。推荐使用rbenv,因为它利用shims文件夹来分离各个Ruby版本,相比RVM更轻便易用。但务必注意,团队内部不应同时使用不同的Ruby环境管理工具,否则可能导致项目编译错误。

rbenv是一款Ruby环境管理工具,能够安装、管理、隔离以及在多个Ruby版本之间进行切换。我们可以通过Homebrew来安装rbenv。以下是安装Homebrewrbenv的脚本:

1
2
3
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

brew install rbenv ruby-build rbenv-vars

安装完rbenv后,我们需要将以下设置信息添加到你的Shell配置文件中,例如~/.bash_profile~/.zshrc等文件。这样可以确保每次打开终端时都会初始化rbenv

1
2
3
4
5
# 设置 rbenv 环境变量
export PATH="$HOME/.rbenv/bin:$PATH"

# 初始化 rbenv
eval "$(rbenv init -)"

4.2 安装和设置项目的 Ruby 环境

1
2
3
$ cd $(PROJECT_DIR)
$ rbenv install 3.2.1
$ rbenv local 3.2.1

在这里,我们将项目的Ruby环境配置为3.2.1版本。rbenv会为我们创建一个名为.ruby-version的文件,该文件只包含一个版本号(例如3.2.1)的字符串。这个包含版本号的文件可以被Git进行管理。如果需要更新版本,可以通过rbenv local命令进行,每次更新也由Git统一管理,这样就能确保其他团队成员使用相同版本的Ruby开发环境。

五、RubyGems 和 Bundler

RubyGemsBundler 主要是用来安装和管理 CocoaPodsfastlane 等第三方工具。

RubyGemsRuby的依赖包管理工具,Ruby世界中的包被称为Gem。我们可以使用gem install命令来安装Gem。然而,RubyGems在管理Gem版本时存在一些不足之处,因此有人开发了BundlerBundler可以检查和安装Gem的特定版本,为Ruby项目提供一致性的环境。

要安装Bundler,可以执行gem install bundler命令。然后,执行bundle init命令可以生成一个Gemfile文件。在这个文件中,像CocoaPodsfastlane等依赖包就可以被添加进去。

1
2
3
source "https://rubygems.org"
gem "cocoapods", "1.15.2"
gem "fastlane", "2.220.0"

注意我们在gem命令里面都指定了依赖包的特定版本号。例如,在我们的 Test App 就使用了1.15.2版的 CocoaPods,然后执行bundle install来安装各个 GemBundler 会自动生成一个 Gemfile.lock 文件来锁定所安装的 Gem 的版本,例如:

1
2
3
DEPENDENCIES
cocoapods (= 1.15.2)
fastlane (= 2.220.0)

为了保证团队其他成员都可以使用版本号一致的 Gem,我们需要把 Gemfile Gemfile.lock 一同保存到 Git 里面统一管理起来。

到此为止,我们已经知道怎样使用 Ruby 工具链配置一个统一的开发环境。但在真实的开发环境中,搭建环境只需要一个人来完成即可,其他成员执行以下脚本就能完成整套开发环境的搭建。

1
2
3
4
5
6
7
8
9
10
11
12
13
# ./scripts/setup.sh

# Install ruby using rbenv
ruby_version=`cat .ruby-version`
if [[ ! -d "$HOME/.rbenv/versions/$ruby_version" ]]; then
rbenv install $ruby_version;
fi
# Install bunlder
gem install bundler
# Install all gems
bundle install
# Install all pods
bundle exec pod install

该脚本主要做了四件事情,第一步是在 rbenv 下安装特定版本的 Ruby 开发环境,然后通过 RubyGems 安装 Bunlder,接着使用 Bundler 安装 CocoaPodsfastlane 等依赖包,最后安装各个 Pod。这样,一个统一的项目环境就搭建完成了