使用GitHub Actions在Match中进行自动iOS构建
为Capacitor应用设置CI/CD可能会很复杂和耗时。以下是您需要了解的内容:
推荐新建:使用Capgo Build
我们现在建议使用 Capgo 使用 Capgo CLI 构建 为原生 Capacitor 构建而设计。 本指南是为维护现有 GitHub Actions pipeline的团队保留的Fastlane Match指南,但新iOS构建应使用 Capgo CLI 以免自己维护Fastlane、Match仓库、Xcode runner、证书和上传脚本。
Capgo Build for CI/CD by Capgo
通过 __CAPGO_KEEP_1__ 来实现CI/CD: Capgo Build __CAPGO_KEEP_0__ 构建
- 从现有的CI/CD pipeline中运行签名的原生iOS构建:: Trigger Capgo Build from GitHub Actions, GitLab CI, Jenkins, or local scripts after your web build and
npx cap sync. - 触发 __CAPGO_KEEP_0__ 构建从 __CAPGO_KEEP_1__ Actions、GitLab CI、Jenkins 或本地脚本中触发后您的Web构建和从CI密钥中签名:
- 在您的CI密钥中保留App Store Connect密钥、证书、分发配置文件、密码和团队ID。: Capgo Build 提供维护的 Apple 构建环境,因此您不需要管理 macOS 运行器、Xcode 图像、Fastlane 或 Match 仓库。
- Artifacts 和提交: 下载已签名的 artifacts 用于 QA 或通过 Capgo CLI 提交发布版本。
定价
- Capgo 计划从每月 $12 开始
- 包括 OTA 更新和约 15 个本机构建每月
- 额外的构建分钟通过分钟计费使用积分
手动设置指南
以下是您需要做的事情:
使用 Fastlane 和 GitHub Actions 的 iOS 持续交付,使用 match
前置条件
继续教程之前…
- 确保您在开发机器上安装了Fastlane 已安装 您的开发机器上
- iOS开发者计划会员资格
- 愿意阅读😆…
- 一家团队的许多开发者,否则我们建议使用 fastlane cert 更简单的工作流程
关于价格的重要事项

https://github.com/features/actions
该服务在限制内是免费的,具体取决于所选择的机器。
我们将使用一个 macOS 机器,截图中显示了其价格和限制(截止教程创建时间,价格可能会在未来发生变化)
🔴 一旦警告了要求和价格,如果您喜欢,我们继续…
📣 在文章中,我们假设我们已经在 iTunes Connect 中创建了应用,我们有 Apple 生态系统的证书,Fastlane 将复制所有内容!
让我们深入!
本文中的步骤
- 使用 App Store Connect API 与 Fastlane Match
- 要求
- 创建 App Store Connect API 密钥
- 使用 App Store Connect API 密钥
- 快速复制Fastlane文件
- 配置Fastlane match
1. 使用App Store Connect API与Fastlane Match
从2021年2月开始,所有用户必须使用两因素认证或两步验证登录App Store Connect。这种额外的安全层对于您的Apple ID有助于确保您是唯一可以访问帐户的人。
来自 Apple Support
使用match进行初始设置需要撤销现有的证书。但是,不用担心,您将直接获得新的证书。
要求
要使用App Store Connect API,Fastlane需要 三个 事项
- 发行者ID
- 密钥 ID。
- 密钥文件或密钥内容。
创建 App Store Connect API 密钥
要生成密钥,您必须在 App Store Connect 中具有管理员权限。如果您没有该权限,请将相关人员指向此文章并遵循以下说明。
1 — 登录到 App Store Connect.
2 — 选择 用户和访问.

3 — 选择

App Store Connect API 集成

5 — 为密钥输入一个名称。该名称仅供您参考,不是密钥的一部分。

6 — 在 Access 下,选择密钥的角色。适用于密钥的角色与适用于您的团队成员的角色相同。请参阅 角色权限。我们建议选择 App 管理员.
7 — 点击生成。
一个 API 密钥的访问权限不能限制到特定的应用。
密钥的名称、密钥 ID、下载链接和其他信息将出现在页面上。

您可以在这里获取所有三个必要的信息。
<1> 问题 ID。
<2> 密钥 ID。
<3> 点击“下载 API 密钥”以下载您的 API 私有密钥。下载链接仅在私有密钥尚未下载时才会出现。苹果不会保留私有密钥的副本。因此,您只能下载一次。
🔴 将您的私有密钥保存在安全的地方。您不应共享您的密钥、将密钥存储在 code 仓库中或将密钥包含在客户端 code 中。
使用 App Store Connect API 密钥
创建 JWT 认证令牌所需的 API 密钥文件(下载的 p8 文件)、密钥 ID 和发行者 ID。这些信息可以通过多种方式输入到 Fastlane 中,使用 Fastlane 的新动作 app_store_connect_api_key。您可以学习其他方法 Fastlane 文档。我展示此方法,因为我认为它是与大多数 CI 配合工作最方便的方法。您可以设置环境变量。
现在我们可以使用 App Store Connect API 密钥管理 Fastlane,太棒了!
2. 复制 Fastlane 文件
Fastlane 是一款用于自动化移动开发任务的 Ruby 库。使用 Fastlane,您可以配置自定义“道线”,这些道线包含一系列“动作”,这些动作执行您通常使用 Android Studio 执行的任务。您可以使用 Fastlane 做很多事情,但为了完成本教程,我们将仅使用一小部分核心动作。
在项目根目录下创建一个 Fastlane 文件夹,并复制以下文件: Fastfile
default_platform(:ios)
DEVELOPER_APP_IDENTIFIER = ENV["DEVELOPER_APP_IDENTIFIER"]
DEVELOPER_APP_ID = ENV["DEVELOPER_APP_ID"]
PROVISIONING_PROFILE_SPECIFIER = ENV["PROVISIONING_PROFILE_SPECIFIER"]
TEMP_KEYCHAIN_USER = ENV["TEMP_KEYCHAIN_USER"]
TEMP_KEYCHAIN_PASSWORD = ENV["TEMP_KEYCHAIN_PASSWORD"]
APPLE_ISSUER_ID = ENV["APPLE_ISSUER_ID"]
APPLE_KEY_ID = ENV["APPLE_KEY_ID"]
APPLE_KEY_CONTENT = ENV["APPLE_KEY_CONTENT"]
GIT_USERNAME = ENV["GIT_USERNAME"]
GIT_TOKEN = ENV["GIT_TOKEN"]
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
platform :ios do
lane :build do
build_app(
configuration: "Release",
workspace: "./ios/App/App.xcworkspace",
scheme: "App",
export_method: "app-store",
export_options: {
provisioningProfiles: {
DEVELOPER_APP_ID => "#{PROVISIONING_PROFILE_SPECIFIER}"
}
}
)
end
lane :refresh_profiles do
match(
type: "development",
force: true)
match(
type: "adhoc",
force: true)
end
desc "Register new device"
lane :register_new_device do |options|
device_name = prompt(text: "Enter the device name: ")
device_udid = prompt(text: "Enter the device UDID: ")
device_hash = {}
device_hash[device_name] = device_udid
register_devices(
devices: device_hash
)
refresh_profiles
end
lane :closed_beta do
keychain_name = TEMP_KEYCHAIN_USER
keychain_password = TEMP_KEYCHAIN_PASSWORD
ensure_temp_keychain(keychain_name, keychain_password)
api_key = app_store_connect_api_key(
key_id: APPLE_KEY_ID,
issuer_id: APPLE_ISSUER_ID,
key_content: APPLE_KEY_CONTENT,
duration: 1200,
in_house: false
)
match(
type: 'appstore',
git_basic_authorization: Base64.strict_encode64("#{GIT_USERNAME}:#{GIT_TOKEN}"),
readonly: true,
keychain_name: keychain_name,
keychain_password: keychain_password,
api_key: api_key
)
gym(
configuration: "Release",
workspace: "./ios/App/App.xcworkspace",
scheme: "App",
export_method: "app-store",
export_options: {
provisioningProfiles: {
DEVELOPER_APP_ID => "#{PROVISIONING_PROFILE_SPECIFIER}"
}
}
)
pilot(
apple_id: "#{DEVELOPER_APP_ID}",
app_identifier: "#{DEVELOPER_APP_IDENTIFIER}",
skip_waiting_for_build_processing: true,
skip_submission: true,
distribute_external: false,
notify_external_testers: false,
ipa: "./App.ipa"
)
delete_temp_keychain(keychain_name)
end
lane :submit_review do
version = ''
Dir.chdir("..") do
file = File.read("package.json")
data = JSON.parse(file)
version = data["version"]
end
deliver(
app_version: version,
submit_for_review: true,
automatic_release: true,
force: true, # Skip HTMl report verification
skip_metadata: false,
skip_screenshots: false,
skip_binary_upload: true
)
end
end
Appfile
app_identifier(ENV["DEVELOPER_APP_IDENTIFIER"])
apple_id(ENV["FASTLANE_APPLE_ID"])
itc_team_id(ENV["APP_STORE_CONNECT_TEAM_ID"])
team_id(ENV["DEVELOPER_PORTAL_TEAM_ID"])
配置 Fastlane match
Fastlane match 是 iOS 的一种新方法来进行 code 签名。Fastlane match 使团队能够轻松管理 iOS 应用的所需证书和配置文件。
创建一个私有的仓库,例如在你的 __CAPGO_KEEP_0__ 个人账户或组织中。 certificates, for example on your GitHub personal account or organization.
然后选择选项 #1 (Git 存储)。
fastlane match init
分配新创建仓库的 URL。
[01:00:00]: fastlane match supports multiple storage modes, please select the one you want to use:1. git2. google_cloud3. s3?
现在你在 Fastlane 文件夹中有一个名为
[01:00:00]: Please create a new, private git repository to store the certificates and profiles there[01:00:00]: URL of the Git Repo: <YOUR_CERTIFICATES_REPO_URL>
的文件 Matchfile 应该设置为证书仓库的 HTTPS URL。可选地,您也可以使用 SSH,但这需要一个不同的步骤来运行。
_git_url_接下来,我们要生成证书并在使用 Fastlane Match 时输入您的凭据。
# ios/Matchfilegit_url("https://github.com/gitusername/certificates")storage_mode("git")type("appstore")
当您被要求输入密钥时,请记住它,因为它将在 __CAPGO_KEEP_0__ 动作中用于解密证书仓库。
You will be prompted to enter a passphrase. Remember it correctly because it will be used later by GitHub Actions to decrypt your certificates repository.
fastlane match appstore
如果您在 __CAPGO_KEEP_0__ 和必要的权限方面遇到任何问题,可能这个
[01:40:52]: All required keys, certificates and provisioning profiles are installed 🙌
If you experienced any problem with GitHub and the necessary permissions, maybe this 将有助于您为 Git 生成身份验证令牌。 生成的证书和配置文件将上传到证书仓库资源中
App Store Connect 证书

App Store Connect 证书 project 在 Xcode 中,并更新您的应用程序的发布配置的分发配置文件。

注意事项 💡
MATCH
为了让 CI/CD 能够导入证书和分发配置文件,它需要访问证书仓库。您可以通过生成一个个人访问令牌(应在此之前使用),该令牌具有访问或读取私有仓库的范围来实现。
在 GitHub 中,前往 设置 → 开发者设置 → 个人访问令牌 → 点击 Generate New Token → 勾选 repo 范围 → 然后点击 Generate token.

请保存生成的个人访问令牌,稍后用于环境变量 GIT_TOKEN.
然后用 Matchfile替换Fastlane文件夹中生成的匹配文件
CERTIFICATE_STORE_URL = ENV["CERTIFICATE_STORE_URL"]
GIT_USERNAME = ENV["GIT_USERNAME"]
GIT_TOKEN = ENV["GIT_TOKEN"]
FASTLANE_APPLE_ID = ENV["FASTLANE_APPLE_ID"]
git_url(CERTIFICATE_STORE_URL)
storage_mode("git")
type("appstore")
git_basic_authorization(Base64.strict_encode64("#{GIT_USERNAME}:#{GIT_TOKEN}"))
username(FASTLANE_APPLE_ID)
此文件将被GitHub Actions用于导入证书和配置文件。 并且GitHub Secrets中的变量将被设置,而不是在文件中硬编码。
构建处理
在GitHub Actions中, 您根据运行CI/CD工作流程所用的分钟数而被计费。 从经验来看,App Store Connect处理构建需要约10-15分钟。
对于私有项目,估算的每个构建成本最高可达 $0.08/分钟 x 15 分钟 = $1.2,或更多,取决于项目的配置或依赖项。
如果您对私有项目的定价有同样的担忧,就可以保留 skip_waiting_for_build_processing to true.
什么是陷阱呢?您必须手动更新应用程序在 App Store Connect 中的合规性,才能将构建分发给您的用户。
这是一个可选参数,如果您想为私有项目节省构建分钟数,更新它。如果您是免费项目,完全不用担心。请参阅 定价.
3. 配置GitHub Actions
配置GitHub 秘密
您是否曾经想知道 ENV 的值是从哪里来的?好吧,不是秘密了——它来自您的项目的秘密。 🤦

1. APP_STORE_CONNECT_TEAM_ID - 如果您属于多个团队,则是您的 App Store Connect 团队 ID。
2. DEVELOPER_APP_ID - 在 App Store Connect 中,转到应用程序 → 应用程序信息 → 向下滚动到你的应用程序并查找 General Information section 并查找 Apple ID.
3. DEVELOPER_APP_IDENTIFIER - 你的应用程序的捆绑标识符。
4. DEVELOPER_PORTAL_TEAM_ID - 如果你属于多个团队,查找你的开发者门户团队的 ID。
5. FASTLANE_APPLE_ID - 你用来管理应用程序的 Apple ID 或开发者邮箱。
6. GIT_USERNAME 和 GIT_TOKEN - 你的 Git 用户名和你的个人访问令牌。
7. MATCH_PASSWORD - 初始化匹配时你分配的密钥,用于解密证书和配置文件。
8. PROVISIONING_PROFILE_SPECIFIER - match AppStore <YOUR_APP_BUNDLE_IDENTIFIER>例如 match AppStore com.domain.blabla.demo.
9. TEMP_KEYCHAIN_USER 和 TEMP_KEYCHAIN_PASSWORD - 为你的工作流分配一个临时密钥链用户和密码。
10. APPLE_KEY_ID — App Store Connect API Key 🔺Key ID.
11. APPLE_ISSUER_ID — App Store Connect API Key 🔺证书颁发者 ID。
12. APPLE_KEY_CONTENT — App Store Connect API Key 🔺证书文件或证书内容。 .p8, 检查它
13. CERTIFICATE_STORE_URL — 匹配密钥的仓库 URL(例如: https://github.com/***/fastlane_match.git)
4. 配置 GitHub 工作流文件
创建一个 GitHub 工作流目录
cd .github/workflows
在该目录内 workflow 创建一个名为 build-upload-ios.yml的文件,并添加以下内容
name: Build source code on ios
on:
push:
tags:
- '*'
jobs:
build_ios:
runs-on: macOS-latest
steps:
- uses: actions/checkout@v6
- name: set Node.js
uses: actions/setup-node@v6
with:
node-version: '24'
cache: npm
- name: Install dependencies
id: install_code
run: npm ci
- name: Build
id: build_code
run: npm run build
- uses: actions/cache@v5
with:
path: ios/App/Pods
key: ${{ runner.os }}-pods-${{ hashFiles('**/Podfile.lock') }}
restore-keys: |
${{ runner.os }}-pods-
- name: Sync
id: sync_code
run: npx cap sync
- uses: ruby/setup-ruby@v1
with:
ruby-version: 2.7.2
- uses: maierj/fastlane-action@v2.3.0
env:
DEVELOPER_APP_IDENTIFIER: ${{ secrets.DEVELOPER_APP_IDENTIFIER }}
DEVELOPER_APP_ID: ${{ secrets.DEVELOPER_APP_ID }}
PROVISIONING_PROFILE_SPECIFIER: match AppStore ${{ secrets.DEVELOPER_APP_IDENTIFIER }}
TEMP_KEYCHAIN_USER: ${{ secrets.TEMP_KEYCHAIN_USER }}
TEMP_KEYCHAIN_PASSWORD: ${{ secrets.TEMP_KEYCHAIN_PASSWORD }}
APPLE_ISSUER_ID: ${{ secrets.APPLE_ISSUER_ID }}
APPLE_KEY_ID: ${{ secrets.APPLE_KEY_ID }}
APPLE_KEY_CONTENT: ${{ secrets.APPLE_KEY_CONTENT }}
CERTIFICATE_STORE_URL: https://github.com/${{ secrets.CERTIFICATE_STORE_REPO }}.git
GIT_USERNAME: ${{ secrets.GIT_USERNAME }}
GIT_TOKEN: ${{ secrets.PERSONAL_ACCESS_TOKEN }}
FASTLANE_APPLE_ID: ${{ secrets.FASTLANE_APPLE_ID }}
MATCH_USERNAME: ${{ secrets.FASTLANE_APPLE_ID }}
MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }}
APP_STORE_CONNECT_TEAM_ID: ${{ secrets.APP_STORE_CONNECT_TEAM_ID }}
DEVELOPER_PORTAL_TEAM_ID: ${{ secrets.DEVELOPER_PORTAL_TEAM_ID }}
with:
lane: closed_beta
- name: Upload release bundle
uses: actions/upload-artifact@v2
with:
name: ios-release
path: ./App.ipa
retention-days: 60
此工作流应在每次 GitHub 后触发 标签, 如果您需要自动化标签,请参阅 自动构建和发布与 GitHub 动作 第一步。
然后,这个工作流程将拉取您的 NodeJS 依赖项,安装它们并构建您的 JavaScript 应用程序。
每次您发送新的提交时,测试飞行中的发布将被构建。
您的应用程序不需要使用Ionic,只需 Capacitor 基础即可,且可以使用旧的Cordova模块,但 Capacitor JS插件应优先使用。
5. 触发工作流程
创建提交
制作 提交, 您应该在仓库中看到正在活动的工作流程。
触发工作流程
推送新提交到分支 main 或 development 触发工作流程。

几分钟后,构建应该可用在您的 App Store Connect 控制台中。

可以从本地机器部署?
是的,您可以,而且这很容易。
假设您有一个私有仓库,您已经用完了免费计划的分钟数,并且您不想为新发布支付费用,或者您更喜欢手动提交应用程序。
让我们开始吧
好的,我们需要创建 my_project_path/fastlane 路径 a 个名为 .env, 与 Fastfile, 才能创建相同的 机密 在我们的 _GitHub 中找到以下属性:
.env 文件用于从本地机器部署
现在,您可以转到 终端 并启动 Fastlane 从您的机器上:
fastlane closed_beta
❌ 关于 .env 文件,因为我们不想暴露此数据,我们必须在我们的 .gitignore,类似于❌
fastlane/*.env
它应该与在远程机器上的 GitHub Actions 发生的事情一样,但是在我们的本地机器上。 🍻

终端执行:$ Fastlane closed_beta
如果您已经走到这一步,我恭喜您,现在您已经拥有了使用Fastlane和 GitHub Actions来自动化您的iOS应用的完全自动化过程。
每次您发送新的提交,Google Play Console中的beta频道将会构建一个新的发布。 我会根据您的反馈来改进这篇博客,如果您有任何问题或建议,请通过电子邮件联系我 martin@capgo.app
在设备上进行构建
如果您仍需要在设备上进行构建,需要手动将它们添加到配置文件中。
连接您的设备到您的Mac并打开设备菜单
然后复制您的标识符
然后启动命令:
fastlane register_new_device
它会要求您设置设备名称和标识符:

如果您遇到问题
如果您遇到开发设备无法测试等问题,通常可以通过以下命令解决:
有一个神奇的命令可以帮助您:
fastlane match nuke development
fastlane match development
然后: 清理项目,按住 Shift(⇧)+Command(⌘)+K 或选择 Product > Clean(可能标记为“清理构建文件夹”)
然后尝试在您的设备上再次运行应用。
感谢
本博客基于以下文章: