为Capacitor应用设置CI/CD可能会很复杂和耗时。以下是您需要知道的内容:
新建推荐:使用Capgo Build
我们现在建议使用 Capgo Build与CapgoCLI 用于本机Capacitor构建。 本 Fastlane 指南保留用于维护现有 GitHub Actions pipeline 的团队,但新 iOS 构建应使用 Capgo CLI 以免您自己维护 Fastlane、Xcode 运行器、证书和上传脚本。
前提条件
开始之前,您需要设置:
- 具有管理员权限的 GitHub 账户
- iOS 开发者计划会员资格
- 具有适当权限的 App Store Connect API 访问权限
- 对 GitHub Actions 工作流程的理解
- Fastlane 配置的知识
- 维护和调试管道所需的时间
- 适当的证书和分发配置文件
Professional CI/CD Setup by Capgo
避免复杂性 Capgo __CAPGO_KEEP_0__直接在您偏好的平台中配置您的CI/CD管道:
- 平台独立性: 与GitHub Actions、GitLab CI 或其他平台兼容
- 无缝集成: 不需要切换平台,兼容您的当前流程
- 定制配置: 根据您的项目需求进行个性化设置
- 专业指导: 我们已经为50+个应用程序设置了CI/CD
定价
- 一次性设置费用:$2,600
- Your running costs: ~$300/year
- 与其他专有解决方案相比:$6,000/year
- 在 5 年内节省 $26,100
手动设置指南
如果您仍想自己设置一切,请遵循以下步骤:
使用 Fastlane 和 GitHub 动作和证书的 iOS 持续交付
前提条件
在继续教程之前:
- 确保您在开发机器上安装了 Fastlane 已安装 Make sure you have Fastlane installed on your development machine.
- 确保您是iOS开发者计划成员。
价格相关的重要信息

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

3 — 选择 Integration 标签。

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

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

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

您可以在这里获取所有三个必要的信息。
<1> Issue ID. (APPLE_ISSUER_ID 密钥)
<2> Key ID. (APPLE_KEY_ID 密钥)
<3> 点击“下载API密钥”下载您的API私钥。下载链接只有在私钥尚未下载时才会出现。Apple不会保留私钥的副本。因此,您只能下载一次。
🔴 将您的私钥存储在安全的地方。您不应共享您的密钥、将密钥存储在code仓库中或将密钥包含在客户端code中。
使用App Store ConnectAPI密钥
The API Key 文件(下载的 p8 文件)、密钥 ID 和发行者 ID 必须要在创建 JWT 认证令牌时使用。有多种方式可以将此信息传递给 Fastlane。 我选择使用 Fastlane 的新动作 app_store_connect_api_key您可以在 Fastlane 文档中学习其他方法。 我展示这个方法,因为我认为它是与大多数 CI 工作最方便的方式,
您可以设置环境变量。APPLE_KEY_CONTENT).
base64 -i APPLE_KEY_CONTENT.p8 | pbcopy
Now we can manage the App Store Connect with Fastlane using the API key, great!
现在我们可以使用 __CAPGO_KEEP_0__ key 在 Fastlane 中管理 App Store Connect,太棒了!
2. 证书 打开 XCode 并前往 > 设置 > 账户 > Apple ID 选择您的团队。

点击 管理证书.
如果您尚未创建证书,请创建新证书。
点击 + 选择 苹果分发

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

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

并选择 App Store Connect.

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

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

生成 名称将用于在Fastlane中识别配置文件,值为.
生成配置文件
APPLE_PROFILE_NAME.

文件。 .mobileprovision 下载配置文件

请将配置文件转换为 Base64 并将其存储为一个密钥(BUILD_PROVISION_PROFILE_BASE64).
base64 -i BUILD_PROVISION_PROFILE.mobileprovision | pbcopy
4. 复制 Fastlane 文件
Fastlane 是一个用于自动化移动开发任务的 Ruby 库。使用 Fastlane,您可以配置自定义的“道线”(lanes),这些道线包含一系列的“动作”(actions),这些动作执行您通常使用 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 使用您在下一步中配置的仓库密钥。您只需要一个本地文件,如果您想在自己的机器上运行或测试 Fastlane。 .env 4. Copy Fastlane files
为了本地测试,创建 <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中设置的值。
bundle-identifier-xcode
In GitHub Actions, 您根据CI/CD工作流程的运行分钟数进行计费。从我的经验来看,需要约10-15分钟才能在App Store Connect中处理构建。 对于私有项目,估计每个构建的成本可以达到
$0.08/分钟 x 15分钟 = $1.2 ,或更多,取决于您的项目的配置和依赖项。如果您对私有项目的成本有所担忧,可以设置
。这将通过不等待App Store Connect完成处理构建来节省构建分钟数。 skip_waiting_for_build_processing 然而,这也意味着您需要手动更新您的应用的合规信息在App Store Connect中,以便可以将构建分发给用户。 true这种优化主要适用于私有项目,因为构建分钟数会花费钱。对于公共/免费项目,构建分钟数是免费的,所以没有必要启用此设置。请参见__CAPGO_KEEP_0__的
价格页面
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 __CAPGO_KEEP_0__ pricing page
7. 配置 GitHub 动作
配置 GitHub 秘密
请从文件中复制并粘贴这些秘密到 __CAPGO_KEEP_0__ 仓库中的秘密 .env file and paste them into the GitHub repository secrets.
设置 秘密和变量 > 动作 > 新仓库秘密 > __CAPGO_KEEP_0__-秘密
2. BUILD_CERTIFICATE_BASE64 - 基础64编码的配置文件
3. BUILD_PROVISION_PROFILE_BASE64 - 基础64编码的配置文件
4. BUNDLE_IDENTIFIER - 你的应用程序的包标识符。
5. APPLE_KEY_ID — App Store Connect API Key 🔺Key ID。
6. APPLE_ISSUER_ID — App Store Connect API Key 🔺发行者 ID。
7. APPLE_KEY_CONTENT — App Store Connect API Key 🔺密钥内容。 .p8, 检查它
8. 配置 GitHub 工作流文件
创建一个 GitHub 工作流目录。
cd .github/workflows
在文件夹内,创建一个名为 workflow 并添加以下内容。 build-upload-ios.yml这个工作流应该在每次 __CAPGO_KEEP_0__ 后触发。
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
This workflow should be triggered after each GitHub 标签, 如果您需要自动化标签,请参阅 自动构建和发布与 GitHub 动作 第一步。
然后,这个工作流程将拉取您的 NodeJS 依赖项,安装它们并构建您的 JavaScript 应用程序。
每次您发送新的提交时,测试飞行中的发布将被构建。
您的 App 不需要使用 Ionic,只需 Capacitor 基础即可,它可以具有旧的 Cordova 模块,但 Capacitor JS 插件应优先使用。
8. 触发工作流程
创建一个提交
制作一个 提交, 您应该在仓库中看到正在活动的工作流程。
触发工作流程
推送新提交到分支 main 或 development 触发工作流程。

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

9. 我可以从本地机器部署吗?
是的,您可以,而且非常方便。
您可以使用 Xcode 构建和签名您的应用程序,正如往常一样。
相关文章
CI/CD 设置指南
- 自动 Capacitor Android 构建与 GitHub Actions - 完整的 Android CI/CD 设置
- 自动构建和发布与 GitHub Actions - 全面的 CI/CD pipeline 教程
- 使用 GitHub Actions 管理开发和生产构建 - 环境管理
- 自动 Capacitor iOS 构建与 Match - 使用 Fastlane Match 的替代方案
替代 CI/CD 平台
- 使用 GitLab CI 构建 - GitLab 替代方案
- 使用 CodeMagic 构建 - __CAPGO_KEEP_0__
实时更新 & 部署
- Capgo 实时更新文档 - 为您的应用程序添加 OTA 更新
- 与 Capgo 集成 CI/CD - 在管道中集成实时更新
感谢
本博客基于以下文章: