为 Capacitor 应用配置 CI/CD 可能非常复杂且耗时。以下是您需要了解的内容:
新构建推荐方案:使用 Capgo Build
我们现在推荐使用 配合 Capgo CLI 的 Capgo Build 用于原生 Capacitor 构建。 本 Fastlane 指南仅供维护现有 GitHub Actions pipeline 的团队参考。对于新的 iOS 构建,建议使用 Capgo CLI,这样你就无需再手动维护 Fastlane、Xcode runner、证书和上传脚本。
由 Capgo 提供的 CI/CD Capgo Build
无需再维护 Fastlane、Xcode runner、证书、provisioning profile 和上传脚本。 Capgo 构建 通过你现有的 CI/CD pipeline 运行已签名的原生 iOS 构建:
- 完美适配你的 pipeline:在 Web 构建完成后,通过 GitHub Actions、GitLab CI、Jenkins 或本地脚本触发 Capgo Build,并且
npx cap sync. - 使用 CI secrets 进行签名:将 App Store Connect 密钥、证书、provisioning profiles、密码和 Team ID 保存在你自己的 CI secrets 中。
- 无需维护原生 runner:Capgo Build 提供维护良好的 Apple 构建环境,你无需再管理 macOS runner、Xcode 镜像或 Fastlane lanes。
- 构建产物与提交: 下载已签名产物用于 QA,或通过 Capgo CLI 提交发布构建。
定价
- Capgo 方案起售价为 $12/月
- 包含 OTA 更新,每月约 15 次原生构建
- 超出部分的构建时长将通过积分按分钟计费
手动配置指南
你需要执行以下操作:
使用 Fastlane、GitHub Actions 及证书实现 iOS 持续交付
前提条件
在继续本教程之前:
- 确保你的开发机已安装 Fastlane 已安装 。
- 请确保你已加入 iOS 开发者计划。
关于价格的重要信息

https://github.com/features/actions
该服务为“免费" 在限额内免费,具体取决于所选机器。
我们将使用 macOS 机器,你可以在截图中看到其价格和限制(价格为教程编写时的价格,未来可能会有变动)
了解完要求和价格后,让我们继续。
注意:本文假设你已在 App Store Connect 中创建了应用。Fastlane 会自动复制重要信息!
你将通过本教程学到什么
本文的操作步骤
- 配合 Fastlane 使用 App Store Connect API
- 要求:
- 创建 App Store Connect API Key
- 使用 App Store Connect API Key
- 要求:
- 复制 Fastlane 文件
- 配置 GitHub Actions
1. 配合 Fastlane 使用 App Store Connect API
自 2021 年 2 月起,所有用户登录 App Store Connect 时都必须进行双重身份验证或两步验证。为您的 Apple ID 增加这一层安全保护,可以确保只有您本人才能访问账号。
来自 Apple 支持
环境要求
为了让 Fastlane 能够使用 App Store Connect API 来上传您的 App,您需要提供以下 三 项内容:
- 发行者 ID
- Key ID
- Key 文件或 Key 内容
获取 App Store Connect API Key
要生成 Key,您必须拥有 App Store Connect 的 Admin 权限。如果您没有该权限,可以将此文章转发给相关人员。
-
选择 用户和访问.

3 — 选择 Integration 选项卡。

- 点击 Generate API Key 或 (+) 按钮。

- 为 key 输入一个名称。该名称仅供参考,不属于 key 本身。

6 — 在 Access 下,为 key 选择角色。适用于 key 的角色与适用于您团队用户的角色相同。请参阅 角色权限. 我们建议选择 应用管理器.
- 点击 Generate。
API 密钥的访问权限无法限制在特定 App 内。
页面将显示新密钥的名称、Key ID、下载链接及其他信息。

你可以在这里获取所有三项必要信息。
<1> 问题 ID。 (APPLE_ISSUER_ID secret
<2> Key ID。(APPLE_KEY_ID secret
<3> 点击“Download API Key”来下载你的 API 私钥。只有在私钥尚未被下载时,下载链接才会显示。Apple 不会保留私钥副本,因此你只能下载一次。
🔴 请将私钥妥善保存。切勿分享你的密钥,不要将密钥存储在 code 仓库中,也不要将密钥包含在客户端 code 中。
使用 App Store Connect API Key
为了创建用于授权的 JWT token,你需要 API Key 文件(下载的 p8 文件)、Key ID 和 Issuer ID。有多种方式可以将这些信息传递给 Fastlane,我选择了使用 Fastlane 的新 action app_store_connect_api_key。你可以在 Fastlane 文档中了解其他方式。我推荐这种方法,因为我认为对于大多数支持设置环境变量的 CI 来说,这是最简单的方式。
请将下载的 p8 文件转换为 Base64 格式,并将其作为 Secret 存储(APPLE_KEY_CONTENT).
base64 -i APPLE_KEY_CONTENT.p8 | pbcopy
现在我们可以使用 API key 通过 Fastlane 来管理 App Store Connect 了,太棒了!
2. 证书
打开 Xcode 并前往 设置 > 账号 > Apple ID > 团队 并选择您的团队。

点击 管理证书.
如果您尚未创建证书,可以创建一个新证书。
点击 + 并选择 Apple Distribution

然后,你需要前往 Keychain Access,将证书下载为 .p12 文件。
为此,你需要打开 Keychain Access,切换到 login 钥匙串,然后点击 我的证书.

选项卡。接着选择你想要下载的证书(可以通过证书日期进行查找)。
然后右键点击证书上的私钥,并选择 导出.
选择文件格式 个人信息交换 (.p12).
这将以以下格式下载证书: .p12 文件。
请在终端中打开该文件,并使用以下命令将其转换为 Base64:
base64 -i BUILD_CERTIFICATE.p12 | pbcopy
这将成为你的 BUILD_CERTIFICATE_BASE64 secret。此外,当系统提示时,请输入证书密码。该密码即为你的 P12_PASSWORD secret。
3. Provisioning profiles
打开 Apple Developer 并选择正确的团队。
然后点击 +

并选择 App Store Connect.

接着你需要选择正确的 App,请注意不要使用通配符,否则签名会失败。

选择你之前创建的正确证书(查看过期日期,应与今天的月日一致)并点击 继续.

最后输入 Profile 名称并点击 生成.
该名称将用于在 Fastlane 中标识配置文件,其值为
APPLE_PROFILE_NAME.

您可以将配置文件下载为 .mobileprovision 文件。

请将配置文件转换为 Base64 格式,并将其作为 secret 存储(BUILD_PROVISION_PROFILE_BASE64).
base64 -i BUILD_PROVISION_PROFILE.mobileprovision | pbcopy
4. 复制 Fastlane 文件
Fastlane 是一个旨在自动化移动开发常用任务的 Ruby 库。通过 Fastlane,您可以配置自定义“lanes”,这些 lanes 封装了一系列“actions”,用于执行您通常在 Android Studio 中手动完成的任务。Fastlane 功能强大,但在本教程中,我们仅使用其中几个核心 actions。
在您的 Capacitor/Ionic 项目根目录下创建 Fastlane 文件夹,并在其中添加 Fastfile:
- 文件夹:
<project-root>/fastlane/ - 文件:
<project-root>/fastlane/Fastfile
这与 ... 处于同一层级 package.json, capacitor.config.*,并且 ios/ 文件夹。请勿在 ... 内部创建它 ios/App/.
platform :ios do
desc 'Export ipa and submit to TestFlight'
lane :beta do
keychain_info = { keychain_name: "ios-build-#{Time.now.to_i}.keychain", keychain_password: SecureRandom.uuid }
begin
setup_signing(keychain_info)
bump_build_number
build_app_with_signing(keychain_info)
submit_to_testflight
ensure
cleanup_keychain(keychain_info)
end
end
private_lane :setup_signing do |options|
create_keychain(
name: options[:keychain_name],
password: options[:keychain_password],
unlock: true,
timeout: 0,
lock_when_sleeps: false,
add_to_search_list: true
)
import_cert(options)
install_profile
update_project_settings
end
lane :bump_build_number do
file = File.read('../package.json')
data_hash = JSON.parse(file)
api_key = app_store_connect_api_key(
key_id: ENV['APPLE_KEY_ID'],
issuer_id: ENV['APPLE_ISSUER_ID'],
key_content: ENV['APPLE_KEY_CONTENT'],
is_key_content_base64: true,
duration: 1200,
in_house: false
)
build_num = app_store_build_number(
api_key: api_key,
app_identifier: ENV['BUNDLE_IDENTIFIER'],
live: false
)
build_num = build_num + 1
UI.message("Bumped build number to #{build_num}")
increment_build_number(
build_number: build_num,
xcodeproj: "./ios/App/App.xcodeproj",
skip_info_plist: true
)
end
private_lane :import_cert do |options|
cert_path = "#{Dir.tmpdir}/build_certificate.p12"
File.write(cert_path, Base64.decode64(ENV['BUILD_CERTIFICATE_BASE64']))
import_certificate(
certificate_path: cert_path,
certificate_password: ENV['P12_PASSWORD'] || "",
keychain_name: options[:keychain_name],
keychain_password: options[:keychain_password],
log_output: true
)
File.delete(cert_path)
end
private_lane :cleanup_keychain do |options|
delete_keychain(
name: options[:keychain_name]
)
end
private_lane :install_profile do
profile_path = "#{Dir.tmpdir}/build_pp.mobileprovision"
File.write(profile_path, Base64.decode64(ENV['BUILD_PROVISION_PROFILE_BASE64']))
UI.user_error!("Failed to create provisioning profile at #{profile_path}") unless File.exist?(profile_path)
ENV['PROVISIONING_PROFILE_PATH'] = profile_path
install_provisioning_profile(path: profile_path)
File.delete(profile_path)
end
private_lane :update_project_settings do
update_code_signing_settings(
use_automatic_signing: false,
path: "./ios/App/App.xcodeproj",
code_sign_identity: "iPhone Distribution",
profile_name: ENV['APPLE_PROFILE_NAME'],
bundle_identifier: ENV['BUNDLE_IDENTIFIER'],
team_id: ENV['APP_STORE_CONNECT_TEAM_ID']
)
update_project_team(
path: "./ios/App/App.xcodeproj",
teamid: ENV['APP_STORE_CONNECT_TEAM_ID']
)
end
private_lane :build_app_with_signing do |options|
unlock_keychain(
path: options[:keychain_name],
password: options[:keychain_password],
set_default: false
)
build_app(
workspace: "./ios/App/App.xcworkspace",
scheme: "App",
configuration: "Release",
export_method: "app-store",
output_name: "App.ipa",
export_options: {
provisioningProfiles: {
ENV['BUNDLE_IDENTIFIER'] => ENV['APPLE_PROFILE_NAME']
}
},
xcargs: "-verbose",
buildlog_path: "./build_logs",
export_xcargs: "-allowProvisioningUpdates",
)
end
private_lane :submit_to_testflight do
api_key = app_store_connect_api_key(
key_id: ENV['APPLE_KEY_ID'],
issuer_id: ENV['APPLE_ISSUER_ID'],
key_content: ENV['APPLE_KEY_CONTENT'],
is_key_content_base64: true,
duration: 1200,
in_house: false
)
pilot(
api_key: api_key,
skip_waiting_for_build_processing: true,
skip_submission: true,
distribute_external: false,
notify_external_testers: false,
ipa: "./App.ipa"
)
end
end
5. 配置 Secrets
GitHub Actions 会使用你在下一步中配置的仓库 Secrets。只有当你需要在本地机器上运行或测试 Fastlane 时,才需要本地 .env 文件。
如需本地测试,请在 <project-root>/fastlane/.env 旁边创建 Fastfile。请勿提交此文件。将 fastlane/.env 添加到你的 .gitignore 中(或确认它已被忽略)。示例如下:
APP_STORE_CONNECT_TEAM_ID=UVTJ336J2D
BUNDLE_IDENTIFIER=ee.forgr.testfastlane
# See previous section for these secrets
BUILD_CERTIFICATE_BASE64=
BUILD_PROVISION_PROFILE_BASE64=
APPLE_KEY_ID=
APPLE_ISSUER_ID=
APPLE_KEY_CONTENT=
P12_PASSWORD=
APPLE_PROFILE_NAME=
获取 APP_STORE_CONNECT_TEAM_ID
前往 开发者中心 并向下滚动到 Membership details 部分。
该 Team ID 是您需要设置到 APP_STORE_CONNECT_TEAM_ID secret 中的值。
获取 BUNDLE_IDENTIFIER
- 打开 Xcode
- 双击
App在项目导航器中 - 然后点击该标签页
Signing and Capabilities - 复制
Bundle identifier的值。这是你需要在BUNDLE_IDENTIFIERsecret 中的值。
6. 构建处理
在 GitHub Actions 中, 费用将根据你运行 CI/CD 工作流所消耗的 分钟数进行计费。根据我的经验,构建在 App Store Connect 中处理完成大约需要 10–15 分钟。
对于私有项目,每次构建的预估成本可能高达 $0.08/分钟 x 15 分钟 = $1.2,甚至更高,具体取决于项目的配置和依赖项。
如果你担心私有项目的成本,可以设置 skip_waiting_for_build_processing 至 true. 这将通过跳过等待 App Store Connect 完成构建处理的过程,来节省构建时长。
不过,这也有一定的权衡——在向用户分发构建版本之前,你需要手动在 App Store Connect 中更新应用的合规信息。
这种优化主要适用于构建时长需要付费的私有项目。对于公开或免费项目,构建时长是免费的,因此无需开启此设置。详情请参阅 GitHub 的 定价页面 了解更多信息。
7. 设置 GitHub Actions
配置 GitHub secrets
请从以下文件中复制 secrets, .env 并将其粘贴到 GitHub 仓库的 secrets 中。
前往 设置 > Secrets 和 variables > Actions > 新建 repository secret
2. BUILD_CERTIFICATE_BASE64 - Base64 编码的证书。
3. BUILD_PROVISION_PROFILE_BASE64 - Base64 编码的 provisioning profile。
4. BUNDLE_IDENTIFIER - 应用的 bundle identifier。
5. APPLE_KEY_ID — App Store Connect API Key 🔺Key ID。
6. APPLE_ISSUER_ID — App Store Connect API Key 🔺Issuer ID。
7. APPLE_KEY_CONTENT — App Store Connect API Key 🔺 Key 内容为 .p8, 检查它
8. 配置 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: '3.0'
bundler-cache: true
- uses: maierj/fastlane-action@v3.1.0
env:
APP_STORE_CONNECT_TEAM_ID: ${{ secrets.APP_STORE_CONNECT_TEAM_ID }}
BUNDLE_IDENTIFIER: ${{ secrets.BUNDLE_IDENTIFIER }}
BUILD_CERTIFICATE_BASE64: ${{ secrets.BUILD_CERTIFICATE_BASE64 }}
BUILD_PROVISION_PROFILE_BASE64: ${{ secrets.BUILD_PROVISION_PROFILE_BASE64 }}
APPLE_KEY_ID: ${{ secrets.APPLE_KEY_ID }}
APPLE_ISSUER_ID: ${{ secrets.APPLE_ISSUER_ID }}
APPLE_KEY_CONTENT: ${{ secrets.APPLE_KEY_CONTENT }}
P12_PASSWORD: ${{ secrets.P12_PASSWORD }}
APPLE_PROFILE_NAME: ${{ secrets.APPLE_PROFILE_NAME }}
with:
lane: ios beta
- name: Upload release bundle
uses: actions/upload-artifact@v6
with:
name: ios-release
path: ./App.ipa
retention-days: 10
该 workflow 应在每次 GitHub tag后触发。如果你需要实现 tag 自动化,请参考 使用 GitHub actions 实现自动构建与发布 首先。
接着,该 workflow 会拉取 NodeJS 依赖、进行安装并构建你的 JavaScript 应用。
每次你提交新的 commit,系统都会在 TestFlight 中构建一个 release。
你的 App 不一定非要使用 Ionic,只需以 Capacitor 为基础即可。虽然可以保留旧的 Cordova 模块,但建议优先使用 Capacitor JS 插件。
8. 触发 workflow
创建一个 Commit
进行一次 commit,你应该能在仓库中看到正在运行的 workflow。
触发 workflow
将新的 commits 推送到分支 main 或 development 以触发工作流。

几分钟后,构建版本即可在 App Store Connect dashboard 中查看。

9. 我可以从本地机器进行部署吗?
可以,而且非常简单。
你可以像往常一样使用 Xcode 来构建并签名你的 App。
相关文章
CI/CD 设置指南
- 使用 GitHub Actions 实现 Capacitor Android 自动构建 - 完成 Android CI/CD 设置
- 使用 GitHub Actions 实现自动构建与发布 - 完整的 CI/CD pipeline 教程
- 使用 GitHub Actions 管理开发与生产环境 Build - 环境管理
- 使用 Match 实现 Capacitor iOS 自动 Build - 使用 Fastlane Match 的替代方案
其他 CI/CD 平台
- 使用 GitLab CI 进行 Build - GitLab 替代方案
- 使用 CodeMagic 进行 Build - CodeMagic 配置指南
Live Updates 与部署
- Capgo Live Updates 文档 - 为您的 App 添加 OTA 更新
- 通过 Capgo 实现 CI/CD 集成 - 在您的 pipeline 中集成 Live Update
感谢
本文参考了以下文章:
进阶指南:使用 GitHub actions 和证书实现自动 Capacitor iOS build
如果你正在使用 使用 GitHub actions 和证书实现自动 Capacitor iOS build 若要规划 CI/CD 自动化,请将其与 Capgo CI/CD 连接,以实现 Capgo CI/CD 中的产品工作流; Capgo Native Build 连接,以实现 Capgo Native Builds 中的产品工作流; Capgo 集成 连接,以实现 Capgo 集成中的产品工作流; CI/CD 集成 了解 CI/CD 集成的实现细节,并且 GitHub Actions 集成 有关 GitHub Actions 集成的实现细节。