iOS的持续集成和部署给开发者在向客户发送产品时带来信心。TestFlight让开发者可以轻松地将应用发布给早期或测试者,Semaphore是一个快速的CI/CD服务,支持iOS部署到TestFlight。
本文概述了集成和部署管道的步骤。你可以在这里阅读详细的iOS集成指南。
前提条件
- 一个现有的Flutter项目;你可以使用我们的启动程序或通过运行flutter create my_app来创建一个。
- 一个苹果开发者账户(又称开发者账户),用于开发者证书和配置配置文件--99美元/年。
准备一个Flutter(iOS)应用程序
TestFlight
之前,我们讨论了如何使用Adhoc发布将您的Flutter(iOS)应用程序发布到Firebase。现在,我们将使用App Store发布来创建一个iOS部署,允许我们上传并将过程构建到TestFlight。
TestFlight是苹果公司创建的一个工具,为开发者提供无缝的beta测试。用户可以下载TestFlight应用程序,并使用邀请函或公共链接加入beta测试。
在内部测试期间,构建处理后,立即向开发者账户成员发送构建。每次测试,你最多可以邀请100个测试者。
对于外部测试,如果你有开发者账户以外的用户,在你的用户可以下载和测试新的构建之前,需要24-48小时完成审查。每次测试,你最多可以邀请10,000名测试者。
创建一个新的捆绑标识符
捆绑标识符或捆绑ID使您能够唯一地识别您的应用程序。
在大多数情况下,如果您已经在Xcode中打开了您的应用程序,并将一个开发者团队分配给签名和身份,那么捆绑标识符已经在您的开发者账户中创建。如果它在您的开发者账户中不可用,您可以创建一个新的。
创建一个新的捆绑标识符
捆绑标识符或捆绑ID允许你独特地识别你的应用程序。
在大多数情况下,如果您已经在Xcode中打开了您的应用程序,并将一个开发团队分配给签名和身份,那么捆绑标识符已经在您的开发人员帐户中创建。如果它在您的开发者账户中不可用,您可以创建一个新的。

创建一个新的应用程序
为您的应用程序创建捆绑标识符后,现在是时候在App Store Connect上创建应用程序了,您也可以在这里管理应用程序商店的列表和发布。
请确保引用正确的捆绑标识符。

分配捆绑标识符
现在,导航到ios目录,打开Runner.xcworkspace。
使用你之前添加到App Store Connect的同一个应用捆绑标识符。

设置fastlane
fastlane是一个开源工具,它简化了为移动端创建发布的复杂过程。对于iOS来说,它有一个叫fastlane match的工具,它可以完成管理iOS证书和配置配置文件的所有繁重工作。
安装
在继续之前,确保你的开发机器上已经安装了fastlane。如果你没有,请按照这里的步骤进行安装。
为iOS设置fastlane
要初始化fastlane,请运行以下程序:
cd ios && fastlane init && cd
- 选择手动设置:
What would you like to use fastlane for?
1. 📸 Automate screenshots
2. 👩✈️ Automate beta distribution to TestFlight
3. 🚀 Automate App Store distribution
4. 🛠 Manual setup - manually setup your project to automate your tasks
>>> 4
最后,等待所有的包和依赖项被正确安装。
初始化fastlane将创建Appfile和Fastfile文件来配置你的fastlane工作流程。
设置fastlane匹配
要初始化fastlane match,请运行以下程序:
fastlane match init
接下来,选择git来存储开发者证书和配置文件:
fastlane match supports multiple storage modes, please select the one you want to use:
1. git
2. google_cloud
3. s3
然后,输入你的git存储库的URL,例如:github.com/joshuadeguz…
接下来,你会被提示输入一个匹配密码。
最后,在你的匹配文件中把development 替换为appstore :
type("appstore")
生成 fastlane 匹配凭证
现在你已经建立了一个 fastlane 匹配,现在是时候为你的应用程序生成配置文件和证书了。
在你的Matchfile 中,将app_identifier 设置为你的捆绑标识符:
app_identifier(["com.yourapp.example"])
接下来,你需要运行:
fastlane match appstore
或者如果你有多种构建方式,你也可以指定特定的bundle ID,如下图所示:
fastlane match appstore -a com.yourapp.example
接下来,你会被提示输入你的苹果凭证和Git URL。
这一步将生成文件并上传到你的私人Git仓库,同时也将下载文件到你的本地机器。
最后,使用安装在你的机器上的配置文件进行Release构建变体。

设置环境变量
下面你可以看到一个Fastlane加载环境变量的例子:
example_value = ENV["EXAMPLE_VALUE"]
ENV是一个关键字,代表环境变量。你可以用它来防止API密钥或令牌等敏感信息被提交到文件中。Semaphore支持使用环境变量。
要在Semaphore上创建一个环境变量,你将使用sem。阅读此文,了解如何使用sem CLI。
安装sem CLI后,你需要用`sem connect`连接你的Semaphore账户。
如果你没有Semaphore账户,你可以在导游的带领下,设置一个。
接下来,你需要准备以下环境变量的值。
MATCH_GIT_URL
这是你在初始化时分配给fastlane匹配的URL。
MATCH_PASSWORD
这是你在初始化时分配给 fastlane 匹配的口令。
Match_git_authorization
Git授权值是你的用户名和你的个人访问令牌的组合。它允许Semaphore访问你的配置文件和由fastlane匹配生成的证书。你可以在这里创建你的个人访问令牌。
例如,"<your_username>:<your_personal_access_token>"。
fastlane_user & fastlane_password
这些是你在苹果中访问开发者账户时使用的登录凭证,无论是个人使用还是在开发者团队中。
fastlane_apple_application_specific_password
如果你的账户启用了2FA,你应该为Semaphore创建一个应用程序特定的密码。
要做到这一点,请转到appleid.apple.com。
单击 "密码"。
然后,点击 "生成特定应用密码"。
然后,点击 "创建"。
接下来,使用sem命令来创建Semaphore的环境变量:
sem create secret semaphore-flutter2-env \
-e MATCH_GIT_URL="<YOUR_MATCH_GIT_URL>" \
-e MATCH_PASSWORD="<YOUR_MATCH_PASSWORD>" \
-e MATCH_GIT_AUTHORIZATION="<YOUR_GIT_AUTHORIZTION_TOKEN>" \
-e FASTLANE_USER="<YOUR_APPLE_ID_EMAIL>" \
-e FASTLANE_PASSWORD="<YOUR_APPLE_ID_PASSWORD>"\
-e FASTLANE_APPLE_APPLICATION_SPECIFIC_PASSWORD="<YOUR_APPLE_APP_SPECIFIC_PASSWORD"
最后,将以下环境变量添加到你的Fastfile的最上方:
git_authorization = ENV["MATCH_GIT_AUTHORIZATION"]
team_id = ENV["TEAM_ID"]
app_id = ENV["APP_ID"]
app_identifier = ENV["APP_IDENTIFIER"]
provisioning_profile_specifier = ENV["PROVISIONING_PROFILES_SPECIFIER"]
temp_keychain_user = "temp"
temp_keychain_password = "temp"
创建fastlane部署通道
让我们继续在fastlane上设置工作流。
首先,你需要在环境变量下面添加以下命令:
# This is where the environment variables are located
(truncated)
# Add the following
def delete_temp_keychain(name)
delete_keychain(
name: name
) if File.exist? File.expand_path("~/Library/Keychains/#{name}-db")
end
def create_temp_keychain(name, password)
create_keychain(
name: name,
password: password,
unlock: false,
timeout: 0
)
end
def ensure_temp_keychain(name, password)
delete_temp_keychain(name)
create_temp_keychain(name, password)
end
这将用于在CI机器上存储你的应用程序配置文件和证书时创建临时钥匙链。
接下来,就在钥匙链命令的下面,添加以下内容:
platform :ios do
lane :deploy do
# Step 1 - Create keychains
keychain_name = temp_keychain_user
keychain_password = temp_keychain_password
ensure_temp_keychain(keychain_name, keychain_password)
# Step 2 - Download provisioning profiles and certificates
match(
type: 'appstore',
app_identifier: app_identifier,
git_basic_authorization: Base64.strict_encode64(git_authorization),
readonly: true,
keychain_name: keychain_name,
keychain_password: keychain_password
)
# Step 3 - Build the project
gym(
configuration: "Release",
workspace: "Runner.xcworkspace",
scheme: "Runner",
export_method: "app-store",
export_options: {
provisioningProfiles: {
app_id => provisioning_profile_specifier,
}
}
)
# Step 4 - Upload the project
pilot(
apple_id: "#{app_id}",
app_identifier: "#{app_identifier}",
skip_waiting_for_build_processing: true,
skip_submission: true,
distribute_external: false,
notify_external_testers: false,
ipa: "./Runner.ipa"
)
# Step 5 - Delete temporary keychains
delete_temp_keychain(keychain_name)
end
end
这里有几件事需要注意。
钥匙链(步骤1和5)
这将允许你存储你的应用程序配置文件和证书。
下载配置文件和证书(步骤2)
这一步是从你在 fastlane 匹配初始化时创建的私有 Git 仓库中读取并下载配置文件和证书。这将使用你的 Git 授权凭证。
构建项目(第3步)
该步骤通过明确指定捆绑标识符和配置文件来手动构建项目。
上传项目(第4步)
这一步使用你为FASTLANE_USER、FASTLANE_PASSWORD和FASTLANE_APPLE_APPLICATION_SPECIFIC_PASSWORD设置的环境变量来验证CI并将你的构建项目上传到App Store或TestFlight。
将`skip_waiting_for_build_processing`和`skip_submission`设置为 "true "将允许CI提前完成,而不用等待构建处理完成。当你为像Semaphore这样按使用时间收费的CI付费时,这应该会很方便。关于这一点的更多信息可以在这里阅读。
部署到Semaphore
Semaphore
我们现在要用Semaphore来自动部署。Semaphore支持广泛的平台和编程语言,对于你的移动开发需求来说,它是可靠和快速的。Semaphore速度快,并且能很好地利用TestFlight进行移动应用分发。
我在这里写了一份关于Semaphore工作流可视化构建器的详细指南。
创建你的Semaphore项目
在导航栏中,点击 "创建新+"。
然后,选择你的项目的存储库。
接下来,点击 "自定义",手动设置你的工作流程。

设置持续集成管道
你的持续集成管道将通过运行一系列的构建检查、lints和测试,在将一个变化合并到主分支之前检查它是否稳定。
管线
让我们把持续集成管道设置为使用基于Mac的虚拟机代理,因为我们正在为iOS构建。

安装依赖项块
创建一个名为Install Dependencies的块,然后添加一个名为Install and cache Flutter的作业:
checkout
cache restore flutter-packages-$SEMAPHORE_GIT_BRANCH-$(checksum pubspec.yaml),flutter-packages-$(checksum pubspec.yaml),flutter-packages
flutter pub get
cache store flutter-packages-$SEMAPHORE_GIT_BRANCH-$(checksum pubspec.yaml),flutter-packages-$(checksum pubspec.yaml),flutter-packages /root/.pub-cache
Lint 块
添加一个名为Lint的新块,然后添加作业Format和Analyze。
格式化
flutter format --set-exit-if-changed .
分析
flutter analyze .
序言
checkout
cache restore flutter-packages-$SEMAPHORE_GIT_BRANCH-$(checksum pubspec.yaml),flutter-packages-$(checksum pubspec.yaml),flutter-packages
flutter pub get

测试块
添加一个块来运行您的Flutter测试。
运行单元和小部件测试
flutter test test
序幕
checkout
cache restore flutter-packages-$SEMAPHORE_GIT_BRANCH-$(checksum pubspec.yaml),flutter-packages-$(checksum pubspec.yaml),flutter-packages
flutter pub get

可选地,您可以通过点击 "运行工作流"来测试您的工作流。
设置持续部署管道
你的持续部署管道将处理推广,自动或手动,取决于你的需求,并将执行fastlane部署车道,将你的应用程序的构建上传到TestFlight。
设置推广管道
这个设置将在变化落入主干或你指定的任何分支后自动将你的构建推送到TestFlight。
配置部署管道
与主管道类似,我们将使用一个基于Mac的虚拟机环境,并使用macos-xcode13**图像。
接下来,在这个管道中,你还需要一个安装依赖项的块,并设置一个名为安装和缓存Flutter的工作:
checkout
cache restore flutter-packages-$SEMAPHORE_GIT_BRANCH-$(checksum pubspec.yaml),flutter-packages-$(checksum pubspec.yaml),flutter-packages
flutter pub get
cache store flutter-packages-$SEMAPHORE_GIT_BRANCH-$(checksum pubspec.yaml),flutter-packages-$(checksum pubspec.yaml),flutter-packages /root/.pub-cache

接下来,创建一个名为Deploy to TestFlight的区块,作业为**Run Fastlane**。
checkout
cache restore flutter-packages-$SEMAPHORE_GIT_BRANCH-$(checksum pubspec.yaml),flutter-packages-$(checksum pubspec.yaml),flutter-packages
flutter build ios --no-codesign
cd ios
bundle install
cache store
bundle exec fastlane deploy

最后,使用你之前用sem CLI创建的环境变量。

点击 "运行工作流"并提交更改。
测试部署管道
首先,将`set-up-semaphore`分支合并到`master`:
git fetch --all
git merge origin/set-up-semaphore
git push origin master
接下来,将修改推送到master,以触发自动构建推广。
最后,在App Store Connect上检查,看是否构建成功。
这应该是我们应用程序的最终工作流程。

总结
祝贺你!你已经成功地将你的应用程序部署到了测试区。你已经成功地部署了你的应用程序到TestFlight。这应该可以让你更快地迭代你的应用程序的功能,而不用太担心手动发布方面的问题,这是很复杂和耗时的,为你节省了大量的开发时间!