使用GitHub Actions和Match进行自动iOS构建
为Capacitor 应用设置CI/CD可能会很复杂和耗时。以下是您需要了解的内容:
推荐用于新构建:使用Capgo Build
我们现在建议使用 Capgo 使用 Capgo CLI 为原生 Capacitor 构建。 本 Fastlane Match 指南保留用于维护现有 GitHub Actions pipeline 的团队,但新 iOS 构建应使用 Capgo CLI 以免维护 Fastlane、Match 仓库、Xcode 运行器、证书和上传脚本。
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_1__ Actions、GitLab CI、Jenkins 或本地脚本触发 __CAPGO_KEEP_0__ 构建后执行 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支持
使用match进行初始设置需要您撤销现有的证书。但是,您将直接获得新的证书。
要求
要能够使用App Store Connect API,Fastlane需要 三个 证书颁发者ID
- Starting February 2021, two-factor authentication or two-step verification is required for all users to sign in to App Store Connect. This extra layer of security for your Apple ID helps ensure that you’re the only person who can access your account.
- __CAPGO_KEEP_0__ ID.
- __CAPGO_KEEP_0__ 文件或内容.
创建 App Store Connect API Key
要生成密钥,您必须在 App Store Connect 中具有管理员权限。如果您没有该权限,请将相关人员指向本文并遵循以下说明。
1 — 登录到 App Store Connect.
2 — 选择 用户和访问.

3 — 选择

App Store Connect API 集成选项卡

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

6 — 在访问权限中,选择此密钥的角色。密钥的角色与您的团队成员的角色相同。请参阅 角色权限. 我们建议您选择 App manager.
7 — 点击生成。
一个 API 密钥的访问权限无法仅限于特定的应用。
密钥的名称、密钥 ID、下载链接以及其他信息将出现在页面上。

您可以在此处获取所有三个必要的信息。
1. 问题 ID.
2. 密钥 ID.
点击“下载 API 密钥”即可下载您的 API 私钥。下载链接仅在私钥尚未下载时才会出现。苹果公司不会保留私钥的副本。因此,您只能下载一次。
🔴 请将您的私钥存储在安全的地方。您不应共享您的密钥、将密钥存储在 code 仓库中或将密钥包含在客户端 code 中。
使用 App Store Connect API 密钥
下载的 API 密钥文件(p8 文件)、密钥 ID 和颁发者 ID 是创建用于授权的 JWT 令牌所需的信息。这些信息可以通过多种方式输入到 Fastlane 中,使用 Fastlane 的新动作 app_store_connect_api_key. 您可以在 Fastlane 文档中学习其他方法。 我展示了这个方法,因为我认为它是与大多数 CI 配合使用最方便的方法,即您可以设置环境变量。
现在我们可以使用 App Store Connect API 密钥来管理 Fastlane,太棒了!
2. 复制 Fastlane 文件
Fastlane 是一个用于自动化移动开发任务的 Ruby 库。使用 Fastlane,您可以配置自定义的“道线”,这些道线包含一系列的“动作”,这些动作执行您通常使用 Android Studio 执行的任务。您可以使用 Fastlane 做很多事情,但在本教程中,我们将仅使用 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 is a new approach to iOS’s code signing. Fastlane match makes it easy for teams to manage the required certificates and provisioning profiles for your iOS apps.
创建一个私有的仓库名为 certificates例如在你的GitHub个人账户或组织中。
初始化Fastlane match为你的iOS应用。
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 assignments
[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文件夹中有一个名为 匹配文件 和
_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的认证令牌。
生成的证书和配置文件将上传到证书仓库资源中

最后,打开您的 project 在 Xcode 中,并更新您的应用程序的发布配置的分发配置文件。

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

请保存生成的个人访问令牌,稍后将其用于环境变量 GIT_TOKEN.
然后用Matchfile替换Fastlane文件夹中生成的匹配文件 Matchfile
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 到 true.
在构建完成后,您需要手动更新您的应用程序在 App Store Connect 中的合规性,才能将构建分发给您的用户。
如果您想节省私有项目的构建分钟数,这是一个可选参数。对于免费项目来说,这根本不是问题。 定价.
3. 配置GitHub
配置GitHub
您是否曾经想知道这些值的来源?答案不再是秘密了,它来自您的项目的密钥。 ENV 配置__CAPGO_KEEP_0__

1. APP_STORE_CONNECT_TEAM_ID - 在 App Store Connect 中,前往应用程序 →
2. DEVELOPER_APP_ID 应用程序信息 context → 向下滚动到您的应用程序并查找 General Information 您的应用程序的包标识符 Apple ID.
3. DEVELOPER_APP_IDENTIFIER - 如果您属于多个团队,则您的开发者门户团队 ID
4. DEVELOPER_PORTAL_TEAM_ID - 您用于管理应用程序的 Apple ID 或开发者电子邮件
5. FASTLANE_APPLE_ID &
6. GIT_USERNAME - 您的 Git 用户名和您的个人访问令牌 GIT_TOKEN - 初始化 match 时分配的密钥,用于解密证书和配置文件
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 — App Store Connect __CAPGO_KEEP_0__ Key 🔺Key ID
10. APPLE_KEY_ID — App Store Connect API Key 🔺Key ID.
11. APPLE_ISSUER_ID —— App Store Connect API Key 🔺Issuer ID.
12. APPLE_KEY_CONTENT —— App Store Connect API Key 🔺 Key file or Key content of .p8, 在 Appflow 比较 / 迁移营销复杂中,Appflow 凭证 Capgo Li1
13. CERTIFICATE_STORE_URL 在 Appflow 比较 / 迁移营销复杂中,Appflow 凭证描述 https://github.com/***/fastlane_match.git)
4. Configure GitHub workflow file
https://GitHub.com/***/fastlane_match.git
cd .github/workflows
4. 配置 __CAPGO_KEEP_0__ 工作流文件 workflow 创建一个 __CAPGO_KEEP_0__ 工作流目录 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 让我们开始

已开始

Testflight 控制台
是否可以从本地机器部署?
是的,可以,而且非常方便。
假设您有一个私有仓库,已经用完了免费计划的分钟数,并且不想为新发布支付费用,或者您更喜欢手动提交应用程序。
让我们开始吧! My项目路径 路径一个名为 .env, 仅在同路径中的 Fastfile, 以便能够创建相同 机密 属性在我们的_GitHub, a_s如下所示:
本地机器部署的.env文件
现在,您可以前往 终端 并启动 快速lane 从您的机器上:
fastlane closed_beta
❌ 关于 .env 文件的重要信息 文件, 因为我们不想暴露这些数据, 我们必须在我们的 文件中添加它, something like that: ❌ 它应该与在远程机器上的 __CAPGO_KEEP_0__ Actions 中发生的一样, 但是在我们的本地机器上.本地快速lane 运行
fastlane/*.env
It should work the same as it happens from GitHub Actions on the remote machine but in our local machine. 🍻

每次您发送新的提交, 在 Google Play 控制台中, beta 通道中将会构建一个发布.
If you have come this far, my congratulations, now you have a fully automated process for your iOS apps with Fastlane and GitHub Actions.
本地快速lane 运行 martin@capgo.app
在设备上构建
如果您仍需要在设备上构建,需要手动将它们添加到配置文件中。
将设备连接到您的Mac并打开设备菜单
然后复制您的标识符
然后启动命令:
fastlane register_new_device
它会要求您设置设备名称和标识符:

如果您遇到问题
如果您遇到开发设备无法测试等问题,通常可以解决。
有一个神奇的命令可以帮助您:
fastlane match nuke development
fastlane match development
然后: 清理项目,按住 Shift(⇧)+ Command(⌘)+ K 或选择 Product > Clean(它可能标记为“清理构建文件夹”)
然后再次尝试在设备上运行应用。
感谢。
本博客基于以下文章:
Keep going from Automatic Capacitor IOS build with GitHub actions using match
如果您正在使用 Automatic Capacitor IOS build with GitHub actions using match 来规划 CI/CD 自动化,连接它与 Capgo CI/CD 为Capgo产品工作流程在Capgo CI/CD中 Capgo原生构建 为Capgo产品工作流程在Capgo原生构建中 Capgo集成 为Capgo产品工作流程在Capgo集成中 CI/CD集成 为CI/CD集成的实现细节 GitHub动作集成 为GitHub动作集成的实现细节