为 Capacitor 应用设置 CI/CD 可能会很复杂且耗时。以下是您需要了解的内容:
推荐新建构建:使用 Capgo 构建
我们现在建议使用 Capgo 构建与 Capgo CLI 来进行本机 Capacitor 构建。 本 Fastlane 指南保留用于维护现有 GitHub Actions pipeline 的团队,但新 iOS 构建应使用 Capgo CLI 以免自己维护 Fastlane、Xcode 运行器、证书和上传脚本。
Capgo 构建由 Capgo 提供
跳过 Fastlane、Xcode 运行器、证书、配置文件和上传脚本的维护。 Capgo 构建 从您的现有 CI/CD pipeline 运行签名的本机 iOS 构建:
- 与您的 pipeline 一起工作: 在您的 web 构建之后,从 GitHub Actions、GitLab CI、Jenkins 或本地脚本中触发 Capgo 构建
npx cap sync. - 从 CI 秘密中签名: 在 CI 秘密中保留 App Store Connect 密钥、证书、配置文件、密码和团队 ID。
- 无本地运行器维护: Capgo Build 提供维护的 Apple 构建环境,因此您不必管理 macOS 运行器、Xcode 图像或 Fastlane 通道。
- artifact 和提交: 下载签名的 artifact 进行 QA 或通过 Capgo CLI 提交发布版本。
定价
- : Capgo 计划从每月 $12 起
- : 包括 OTA 更新和约 15 个本地构建/月
- : 额外的构建分钟通过信用额度按分钟计费
: 手动设置指南
以下是您需要做的事情:
使用Fastlane和GitHub Actions和证书的iOS持续交付
前提条件
在继续教程之前,请确保您已经完成以下步骤:
- 确保您在开发机器上安装了Fastlane 确保您是iOS开发者计划的成员 关于价格的重要信息
- 价格:__CAPGO_KEEP_0__ Action
https://__CAPGO_KEEP_0__.com/features/actions

https://github.com/features/actions
该服务的价格为免费' 根据选择的机器,最高可达限制。
我们将使用一个 macOS 机器,截图中显示了其价格和限制(价格截至教程创建时,可能会在未来发生变化)
已知需求和价格后,我们继续。
注意:在这篇文章中,我假设您已经在 App Store Connect 中创建了应用。重要信息将由 Fastlane 复制!
本教程中您将学习什么
本教程中您将要遵循的步骤
- 使用 App Store Connect API 和 Fastlane
- 要求:
- 创建 App Store Connect API 密钥
- 使用 App Store Connect API Key
- 要求:
- 复制 Fastlane 文件
- 配置 GitHub 动作
1. 使用 App Store Connect API 与 Fastlane
2021 年 2 月起,所有用户登录 App Store Connect 都需要两因素认证或两步验证。这一额外的安全层对您的 Apple ID 有助于确保您是唯一能够访问帐户的人。
来自 苹果支持
要求
为了让 Fastlane 能够使用 App Store Connect API 上传您的应用,您需要提供以下三件事: 三 颁发者 ID
- __CAPGO_KEEP_0__
- 密钥 ID
- 密钥文件或密钥内容
获取 App Store Connect API 密钥
要生成密钥,您必须在 App Store Connect 中具有管理员权限。如果您没有该权限,请将相关人员指向此文章。
-
登录到 App Store Connect.
-
选择 用户和访问.

3 — 选择 Integration 选项卡。

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

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

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

您可以在这里获取所有三个必要的信息。
1. 问题 ID。 (APPLE_ISSUER_ID 2. 密钥 ID。 (
3. 点击 “下载 __CAPGO_KEEP_0__ 密钥” 下载您的 __CAPGO_KEEP_1__ 私钥。下载链接仅在私钥尚未下载时才会出现。苹果不会保留私钥的副本。因此,您只能下载一次。APPLE_KEY_ID 存储您的私钥在安全的地方。您不应共享您的密钥,存储密钥在 __CAPGO_KEEP_0__ 仓库中,或者将密钥包含在客户端 __CAPGO_KEEP_1__ 中。
<3> Click “Download API Key” to download your API private key. The download link appears only if the private key has not yet been downloaded. Apple does not keep a copy of the private key. So, you can download it only once.
🔴 Store your private key in a safe place. You should never share your keys, store keys in a code repository, or include keys in client-side code.
Using an App Store Connect API Key
The API Key file (p8 file that you download), the key ID, and the issuer ID are required in order to create the JWT token for authorization. There are multiple ways that this information can be passed into Fastlane. I chose to use the Fastlane’s new action app_store_connect_api_key中学习其他方法。 我展示此方法,因为我认为它是与大多数 CI 工作最方便的方式,即您可以设置环境变量。 请将下载的 p8 文件转换为 Base64 并存储为密钥(]}
]}APPLE_KEY_CONTENT).
base64 -i APPLE_KEY_CONTENT.p8 | pbcopy
现在我们可以使用API密钥来管理App Store Connect,太棒了!
2. 证书
打开XCode,进入 设置 > 账户 > Apple ID > 团队 选择您的团队。

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

然后您需要前往钥匙串下载证书作为 .p12 文件。
要实现此操作,请切换到 登录 钥匙串并切换到 My Certificates.

然后您可以选择要下载的证书。 (根据证书的日期查找)
然后右键单击证书上的私钥并选择 导出.
选择文件格式 个人信息交换 (.p12).
这将下载证书作为一个 .p12 文件。
请在终端中打开文件并使用以下命令将其转换为 Base64:
base64 -i BUILD_CERTIFICATE.p12 | pbcopy
这将成为您的 BUILD_CERTIFICATE_BASE64 密钥。另外,当被询问时,请提供证书的密码。这将是您的 P12_PASSWORD 密钥。
3. 配置文件
打开 苹果开发者 并选择正确的团队。
然后创建一个新配置文件,点击 +

并选择 App Store Connect.

然后您需要选择正确的应用程序,注意您不能使用通配符否则签名会失败。

选择您之前创建的正确证书(查找有效期,应与今天相同的日期和月份)并点击 继续.

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

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

请将配置文件转换为Base64并将其存储为一个秘密(BUILD_PROVISION_PROFILE_BASE64).
base64 -i BUILD_PROVISION_PROFILE.mobileprovision | pbcopy
复制Fastlane文件
Fastlane 是一个用来自动化移动开发任务的 Ruby 库。使用 Fastlane,您可以配置自定义的“通道”,这些通道包含一系列的“动作”,这些动作执行您通常使用 Android Studio 执行的任务。您可以在 Fastlane 中做很多事情,但为了完成本教程,我们将只使用一小部分核心动作。
在您的 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. 配置机密
GitHub Actions 使用您在下一步中配置的仓库机密。您只需要一个本地 .env 文件,如果您想在自己的机器上运行或测试 Fastlane。
为了本地测试,请在 <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 中设置的值。
获取 BUNDLE_IDENTIFIER
- 打开 Xcode
- 双击项目导航器中的
App在项目导航器中的 - 然后单击标签
Signing and Capabilities - 复制的值是
Bundle identifier. 这是您需要在BUNDLE_IDENTIFIER中设置的值。
6. 构建处理
在 GitHub Actions 中 您根据运行 CI/CD 工作流的分钟数而被收费。根据我的经验,构建在 App Store Connect 中处理需要约 10–15 分钟。 6. 构建处理
For private projects, the estimated cost per build can go up to $0.08/min x 15 mins = $1.2, or more, depending on the configuration and dependencies of your project.
If you’re concerned about costs for private projects, you can set skip_waiting_for_build_processing to trueThis will save build minutes by not waiting for App Store Connect to finish processing the build.
However, there is a tradeoff - you’ll need to manually update your app’s compliance information in App Store Connect before you can distribute the build to users.
This optimization is mainly useful for private projects where build minutes cost money. For public/free projects, the build minutes are free so there’s no need to enable this setting. See GitHub’s pricing page 7. Setup
7. Setup GitHub Actions
GitHub
请复制这些密钥 .env 从文件中复制并粘贴到GitHub仓库中的机密。
前往 设置 > 机密和变量 > 动作 > 新建仓库机密
2. BUILD_CERTIFICATE_BASE64 - Base64编码的证书。
3. BUILD_PROVISION_PROFILE_BASE64 - Base64 encoded provisioning profile.
4. 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 content of .p8, 在此处查看详细信息。
8. Configure GitHub workflow file
8. 配置 GitHub 工作流文件
cd .github/workflows
创建一个 __CAPGO_KEEP_0__ 工作流目录。 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
此工作流程应在每次GitHub后触发 标签如果您需要自动化标签,请参阅 自动构建和发布与GitHub动作 首先。
然后,这个工作流程将拉取您的NodeJS依赖项,安装它们并构建您的JavaScript应用。
每次您发送新的提交,测试版将会构建。
您的应用程序不需要使用Ionic,只需使用Capacitor基础即可,它可以包含旧的Cordova模块,但CapacitorJS插件应优先使用。
8. 触发工作流程
创建一个提交
制作一个 提交您应该在仓库中看到正在运行的工作流。
触发工作流
推送新提交到分支 main 或者 development 要触发工作流,请

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

9. 我可以从本地机器部署吗?
是的,您可以,而且非常方便。
您可以使用 Xcode 构建和签署您的应用程序,正如往常一样。
相关文章
CI/CD 设置指南
- 自动 Capacitor Android 构建与 GitHub 动作 - 完整的 Android CI/CD 设置
- 自动构建和发布与 GitHub 动作 - 全面的 CI/CD pipeline 教程
- 使用 GitHub 动作管理开发和生产构建 - 环境管理
- 自动 Capacitor iOS 构建与 Match - 使用 Fastlane Match 的替代方案
替代 CI/CD 平台
- 使用 GitLab CI 构建 - GitLab 替代方案
- 使用 CodeMagic 构建 - CodeMagic 配置指南
实时更新 & 部署
- Capgo 实时更新文档 - 为您的应用程序添加 OTA 更新
- CI/CD Integration with Capgo 感谢
本博客基于以下文章:
使用 Fastlane 和 __CAPGO_KEEP_0__ 动作进行 IOS 持续交付
- Continuous delivery for IOS using Fastlane and GitHub actions
- 来自 @mrogunlana 的此 __CAPGO_KEEP_0__ 消息
- This GitHub message from @mrogunlana
- 本GitHub文档
继续使用自动CapacitorIOS构建与GitHub动作证书
如果您正在使用 自动CapacitorIOS构建与GitHub动作证书 来规划CI/CD自动化,连接它与 CapgoCI/CD 为CapgoCI/CD中的产品工作流 Capgo原生构建 为Capgo原生构建中的产品工作流 Capgo集成 为Capgo集成中的产品工作流 __CAPGO_KEEP_0__集成,CI/CD集成 为 CI/CD Integration 的实现细节 GitHub Actions Integration 为 GitHub Actions Integration 的实现细节