使用 Match 通过 GitHub Actions 自动构建 iOS
为 Capacitor 应用配置 CI/CD 可能既复杂又耗时。你需要了解这些:
新构建推荐方案:使用 Capgo Build
我们现在推荐使用 配合 Capgo CLI 使用 Capgo Build 用于原生 Capacitor 构建。 本 Fastlane Match 指南保留给仍在维护现有 GitHub Actions 流水线的团队;但新的 iOS 构建应使用 Capgo CLI,这样你无需自己维护 Fastlane、Match 仓库、Xcode runner、证书和上传脚本。
Capgo 通过 Capgo 进行 CI/CD 构建
无需再维护 Fastlane Match、Xcode runner、证书、provisioning profile 和上传脚本。 Capgo 构建 通过现有的 CI/CD 流水线运行已签名的原生 iOS 构建:
- 适配你的流水线:在 Web 构建完成后,通过 GitHub Actions、GitLab CI、Jenkins 或本地脚本触发 Capgo Build,并
npx cap sync. - 通过 CI secrets 签名:将 App Store Connect 密钥、证书、provisioning profile、密码和 Team ID 保存在你自己的 CI secrets 中。
- 无需维护原生 runner: Capgo Build 提供持续维护的 Apple 构建环境,因此你无需自行管理 macOS runner、Xcode 镜像、Fastlane 或 Match 仓库。
- 产物与提交:下载已签名的产物用于 QA,或通过 Capgo CLI 提交发布构建。
定价
- Capgo 套餐 $12/月起
- 包含 OTA 更新和每月约 15 次 Native Build
- 额外的构建分钟数通过 credits 按分钟计费
手动配置指南
你需要做的是:
使用 Fastlane 和 GitHub Actions 配合 match 实现 iOS 持续交付
前提条件
在继续教程之前……
- 请确保你已安装 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 支持
开始使用 match 需要撤销现有证书。别担心,你会直接获得新证书。
要求
为了能够使用 App Store Connect API,Fastlane 需要 三 以下信息。
- Issuer ID。
- Key ID。
- Key 文件或 Key 内容。
创建 App Store Connect API 密钥
生成密钥需要在 App Store Connect 中拥有 Admin 权限。如果没有该权限,可以将此文章转发给相关人员,并让他们按照以下步骤操作。
1 — 登录 App Store Connect.
2 — 选择 用户与访问权限.

3 — 选择“集成”选项卡。

4 — 点击生成 API 密钥或添加(+)按钮。

5 — 为密钥输入一个名称。该名称仅供您参考,不属于密钥本身。

6 — 在“访问权限”下,选择该密钥的角色。密钥适用的角色与团队中用户适用的角色相同。请参阅 角色权限。我们建议选择 App 管理员.
7 — 点击“生成”。
无法将 API 密钥的访问权限限定到特定 App。
新密钥的名称、密钥 ID、下载链接及其他信息将显示在页面上。

您可以在此处获取全部三项必要信息。
<1> Issue ID。
<2> Key ID。
<3> 点击 “Download API Key” 下载您的 API 私钥。下载链接仅在私钥尚未下载时显示。Apple 不会保留私钥副本,因此您只能下载一次。
🔴 请妥善保管私钥。切勿分享密钥,不要将密钥存储在 code 仓库中,也不要在客户端 code 中包含密钥。
使用 App Store Connect API 密钥
创建用于授权的 JWT token 需要 API 密钥文件(即下载的 p8 文件)、密钥 ID 和 Issuer ID。通过 Fastlane 的新 action,有多种方式可以输入这些信息: app_store_connect_api_key。您可以在 Fastlane 文档中了解其他方式。我介绍这种方法,因为我认为对于大多数支持设置环境变量的 CI 来说,这是最简单的方式。
现在我们可以使用 App Store Connect 的 API 密钥来管理 Fastlane 了,太棒了!
2. 复制 Fastlane 文件
Fastlane 是一个 Ruby 库,用于自动化常见的移动开发任务。使用 Fastlane,你可以配置自定义的 “lanes”,这些 lanes 会打包一系列 “actions”,用来执行你通常会在 Android Studio 中完成的任务。Fastlane 能做很多事,但本教程只会用到少数几个核心 actions。
在项目根目录创建一个 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 应用所需的证书和描述文件。
创建一个名为 certificates的新私有仓库,例如在你的 GitHub 个人账户或组织中。
为你的 iOS 应用初始化 Fastlane match。
fastlane match init
然后选择选项 #1(Git 存储)。
[01:00:00]: fastlane match supports multiple storage modes, please select the one you want to use:1. git2. google_cloud3. s3?
分配新创建仓库的 URL。
[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>
现在,Fastlane 文件夹中有一个名为 Matchfile 以及
_git_url_应设置为证书仓库的 HTTPS URL。你也可以选择使用 SSH,但这需要额外的运行步骤。
# ios/Matchfilegit_url("https://github.com/gitusername/certificates")storage_mode("git")type("appstore")
接下来,我们使用 Fastlane Match 来生成证书,并在提示时输入你的凭据。
系统会提示你输入密码短语。请务必记牢,因为稍后 GitHub Actions 会用它来解密你的证书仓库。
fastlane match appstore
如果一切顺利,你应该会看到如下内容:
[01:40:52]: All required keys, certificates and provisioning profiles are installed 🙌
如果你在 GitHub 及相关权限方面遇到问题,也许这篇 文章 能帮你生成 git 身份验证 token。
生成的证书和 provisioning profiles 会上传到证书仓库资源中

最后,打开你的 project 在 Xcode 中,并更新应用 release 配置的 provisioning profile。

注意事项 💡
MATCH
为了让 CI/CD 导入证书和 provisioning profiles,需要让它能访问证书仓库。你可以生成一个具有访问或读取私有仓库 scope 的 personal access token(应提前使用)来实现。
在 GitHub 中,前往 设置 → 开发者设置 → 个人访问 token → 点击 Generate New Token → 勾选 repo scope → 然后点击 Generate token.

请保存生成的个人访问令牌副本,稍后用于设置环境变量。 GIT_TOKEN.
然后,用 Matchfile 替换 Fastlane 文件夹中生成的 match 文件。
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 工作流所用的 你用于运行 CI/CD 工作流的密钥。根据经验,在 App Store Connect 中处理构建大约需要 10–15 分钟。
对于私有项目,每次构建的预估成本可能高达 $0.08/分钟 x 15 分钟 = $1.2,或者更多,具体取决于项目的配置或依赖项。
如果你和我一样对私有项目的定价有顾虑,你可以保留 skip_waiting_for_build_processing 改为 true.
有什么代价吗?在构建完成后,你必须手动在 App Store Connect 中更新应用的合规性信息,才能将构建版本分发给用户。
这只是一个可选参数,如果你想为私有项目节省构建时长,可以进行更新。对于免费项目,这完全不是问题。详见 定价.
3. 设置 GitHub Actions
配置 GitHub secrets
有没有想过这些值 ENV 是从哪里来的?其实这不再是秘密——它们来自你项目的 secret。🤦

1. APP_STORE_CONNECT_TEAM_ID - 如果你属于多个团队,请提供 App Store Connect 团队的 ID。
2. DEVELOPER_APP_ID - 在 App Store Connect 中,进入应用 → App 信息 → 向下滚动到 General Information 部分,查找 Apple ID.
3. DEVELOPER_APP_IDENTIFIER - 您应用的 bundle identifier。
4. DEVELOPER_PORTAL_TEAM_ID - 如果您属于多个团队,请查找 Developer Portal 团队 ID。
5. FASTLANE_APPLE_ID - 用于管理应用的 Apple ID 或开发者邮箱。
6. GIT_USERNAME & GIT_TOKEN - 你的 git 用户名和个人访问令牌。
7. MATCH_PASSWORD - 初始化 match 时设置的密码短语,用于解密证书和描述文件。
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 密钥 🔺密钥 ID。
11. APPLE_ISSUER_ID — App Store Connect API Key 🔺Issuer ID。
12. APPLE_KEY_CONTENT — App Store Connect API Key 🔺 Key 文件或 Key 内容,文件为 .p8, 检查一下
13. CERTIFICATE_STORE_URL — 你的 Match keys 仓库 URL (例如: https://github.com/***/fastlane_match.git)
4. 配置 GitHub workflow 文件
创建一个 GitHub workflow 目录。
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
此 workflow 应在每次 GitHub 后触发 标签,如果需要自动打 tag,请参考 使用 GitHub actions 自动构建与发布 首先。
接着,这个 workflow 会拉取你的 NodeJS 依赖、安装它们并构建你的 JavaScript 应用。
每次你提交新的 commit,都会在 TestFlight 中构建一个 release。
你的 App 不需要使用 Ionic,只需 Capacitor 基础即可。它可以包含旧的 Cordova 模块,但应优先使用 Capacitor JS 插件。
5. 触发工作流
创建一个 commit
提交一个 提交,你应该能在仓库中看到正在运行的 workflow。
触发 workflow
把新的 commit 推送到分支 main 或 development 来触发工作流。

几分钟后,build 应该就会出现在你的 App Store Connect dashboard 中。

支持从本地机器部署吗?
可以,而且毫不费力。
假设你有一个私有仓库,免费套餐的分钟数已经用完,你不想为新发布付费,或者更想手动提交应用。
那就开始吧
好的,首先我们需要在 my_project_path/fastlane 路径下的一个名为 .env, 就在与 Fastfile, 以便创建相同的 secret 属性,这些属性位于我们的 _GitHub 中,如下所示:
用于从本地机器部署的 .env 文件
现在,你可以前往 终端 并在你的机器上启动 Fastlane :
fastlane closed_beta
❌ 关于 .env 文件的重要提醒:由于不想暴露这些数据,必须将其加入 .gitignore中,类似这样:❌
fastlane/*.env
它应该和远程机器上通过 GitHub Actions 运行的效果一样,只不过是在我们的本地机器上。🍻

终端执行:$ Fastlane closed_beta
如果你看到这里,恭喜你,现在你已经拥有了一套基于 Fastlane 和 GitHub Actions 的 iOS 应用全自动流程。
每次提交新的 commit,都会在 Google Play 控制台的 beta 渠道构建一个 release。 我会根据你的反馈改进这篇博客;如有任何问题或建议,请发邮件告诉我。 martin@capgo.app
在你的设备上构建
如果你仍需要在设备上构建,就需要手动将它们添加到 provisioning 中。
将设备连接到 Mac 并打开设备菜单
然后复制你的标识符
然后运行命令:
fastlane register_new_device
它会提示你设置设备名称和标识符:

如果你遇到问题
如果遇到开发设备无法测试等问题,这通常能解决。
有个“魔法”命令能救你:
fastlane match nuke development
fastlane match development
然后: 按住 Shift(⇧)+Command(⌘)+K 或选择 Product > Clean(可能显示为“Clean Build Folder”)来清理项目
然后尝试在设备上重新运行应用。
感谢
本文参考了以下文章:
继续用 match 通过 GitHub actions 进行 Capacitor iOS 自动构建
如果你正在使用 使用 match 和 GitHub actions 自动构建 Capacitor iOS 规划 CI/CD 自动化,并将其与 Capgo CI/CD 集成 用于 Capgo CI/CD 中的产品工作流, Capgo Native Build 用于 Capgo Native Builds 中的产品工作流, Capgo 集成 用于 Capgo 集成中的产品工作流, CI/CD 集成 了解 CI/CD 集成的实现细节,以及 GitHub Actions 集成 有关 GitHub Actions 集成的实现细节。