要在云端对 Capacitor App 进行签名和构建,您只需创建一次签名材料(Android keystore、iOS 分发证书及 provisioning profile),将其提供给云构建服务,然后通过终端或 CI 触发构建。该服务会编译原生项目、进行签名,并能直接将其上传至 TestFlight 或 Google Play。本指南将涵盖每种签名文件、如何在没有 Mac 的情况下创建它们、如何通过 Capgo Build 进行配置,以及如何安全地实现已签名构建的自动化。
什么是“云端签名”
应用商店仅接受已签名的二进制文件。签名可以证明该构建版本出自您本人,且之后未被他人篡改。在本地开发时,Xcode 和 Android Studio 会隐藏大部分签名细节。但在云端,没有任何操作是默认完成的,因此您需要明确了解涉及哪些文件:
| 平台 | 文件 | 定义 | 用途 |
|---|---|---|---|
| Android | .jks / .keystore |
存放 upload key 的 Keystore | 为 AAB 或 APK 进行签名 |
| Android | 服务账号 .json |
Google Cloud 凭据 | 上传至 Google Play |
| iOS | .p12 |
Apple Distribution 证书及私钥 | IPA 签名 |
| iOS | .mobileprovision |
绑定 Bundle ID、证书与 Capabilities 的 Provisioning profile | 允许 App 运行及分发 |
| iOS | .p8 + Key ID + Issuer ID |
App Store Connect API 密钥 | 上传至 TestFlight 并读取 Build Numbers |
请勿将这些内容提交至 Git。以下所有内容都将存储在您的本地凭据文件或 CI 的 Secret Store 中。
Android 签名
创建上传用的 keystore
如果应用已在 Google Play 上架,请复用现有的 keystore。除非通过 Play Console 重置上传密钥,否则使用不同密钥签署的更新会被拒绝。
对于新应用:
keytool -genkeypair -v \
-storetype PKCS12 \
-keystore release.jks \
-alias upload \
-keyalg RSA -keysize 2048 \
-validity 10000
注意事项:
- Google Play 要求密钥有效期至少到 2033 年 10 月 22 日。
-validity 10000(约 27 年) 即可满足要求。 - 使用 PKCS12 存储类型时,密钥密码与 store 密码相同。
- 手边没有 JDK? Android keystore 生成器 可以在浏览器中生成相同的文件。
Play App Signing 与上传密钥
Google Play 上的新应用使用 Play App Signing。Google 会持有 App 签名密钥 并对用户下载的内容进行重新签名。你的 keystore 是 上传密钥。如果你丢失了它,Play Console 支持可以注册新的上传密钥,所以丢失它只会导致延迟,而不是灾难。但无论如何,请务必备份。
用于上传的服务账号
若要从云端上传,请在 Google Cloud 中创建一个服务账号,启用 Google Play Android Developer API,下载其 JSON 密钥,然后在 Play Console 的 用户和权限 中邀请该服务账号,并授予其应用的发布权限。如下所示,Capgo 的 onboarding 可以通过 Google 登录完成此操作。
iOS 签名
Apple 的三个核心要素
- Apple Distribution certificate。 每个团队只需一个,有效期为一年。Apple 对证书数量有限制,因此请勿为每个开发者都创建一个。
- 描述文件 (Provisioning profile)。 将 Bundle ID、证书以及推送通知等功能权限进行关联。请使用 App Store Connect 描述文件用于 TestFlight 和 App Store,并使用 Ad Hoc 描述文件用于在已注册设备上安装。每个 App Extension(如 Widget、Share Extension、Notification Service)都需要独立的描述文件。
- App Store Connect API 密钥。 在以下路径创建: Users and Access > Integrations 并授予 App Manager 权限。该
.p8文件仅需下载一次。
您需要在 Apple Developer 团队中拥有 Admin 或 Account Holder 权限才能创建这些内容。
无需 Mac 即可创建证书
Keychain Access 流程需要 macOS,但 OpenSSL 在任何地方都能用:
# 1. Private key and certificate signing request
openssl req -new -newkey rsa:2048 -nodes \
-keyout dist.key -out dist.csr \
-subj "/emailAddress=dev@example.com/CN=Example Inc/C=US"
# 2. Upload dist.csr at developer.apple.com > Certificates > + > Apple Distribution
# and download distribution.cer
# 3. Convert and bundle into a .p12
openssl x509 -inform DER -in distribution.cer -out distribution.pem
openssl pkcs12 -export -legacy \
-inkey dist.key -in distribution.pem \
-out distribution.p12 -passout pass:choose-a-password
该 -legacy OpenSSL 3 里这个 flag 很关键:不加的话,macOS 构建机可能导入失败, .p12 并提示 “MAC verification failed”。基于浏览器的 iOS 证书生成器 如果你不想用终端,它也能完成同样的步骤。
然后在开发者门户中创建 provisioning profile (配置文件 > + > App Store Connect),选择你的 App ID 和新证书,然后下载即可。
使用 Capgo Build 配置签名
Capgo 构建 在 Capgo 管理的机器上编译并签名 Capacitor 应用,让你可以在 Windows 或 Linux 上构建 iOS 版本。首先登录并注册应用:
bunx @capgo/cli@latest login
bunx @capgo/cli@latest app add
方案 A:引导式 onboarding(推荐)
bunx @capgo/cli@latest build init --platform ios
bunx @capgo/cli@latest build init --platform android
在 iOS 上,onboarding 会使用你的 App Store Connect API key 来创建或复用发布证书(distribution certificate)和 App Store provisioning profile。在 macOS 上,它还可以引导你创建该 API key。在 Android 上,它会创建或导入 keystore,并可以通过 Google sign-in 配置 Google Cloud 服务账号和 Play Console 邀请。最后,它会提示你开始第一次 build。
方案 B:保存现有文件
如果你已经拥有前几节中的文件:
# iOS
bunx @capgo/cli@latest build credentials save \
--platform ios \
--certificate ./distribution.p12 \
--p12-password "choose-a-password" \
--ios-provisioning-profile ./AppStore.mobileprovision \
--apple-key ./AuthKey_ABC1234567.p8 \
--apple-key-id ABC1234567 \
--apple-issuer-id 00000000-0000-0000-0000-000000000000 \
--apple-team-id TEAM123456
# Android
bunx @capgo/cli@latest build credentials save \
--platform android \
--keystore ./release.jks \
--keystore-alias upload \
--keystore-key-password "store-password" \
--keystore-store-password "store-password" \
--play-config ./play-service-account.json
对于带有 extensions 的应用,请重复 --ios-provisioning-profile 配合 bundleId=path 为每个 target 进行映射:
--ios-provisioning-profile com.example.app=./App.mobileprovision \
--ios-provisioning-profile com.example.app.widget=./Widget.mobileprovision
凭据存储在 ~/.capgo-credentials/credentials.json中,通过 app ID 和 platform 进行键值管理。添加 --local 以将其存储在项目中的 .capgo-credentials.json 中,并将该文件添加到 .gitignore. Check what is saved with bunx @capgo/cli@latest build credentials list.
触发签名构建
准备原生项目,然后请求构建:
bun run build
bunx cap sync
# iOS: sign with the App Store profile and upload to TestFlight
bunx @capgo/cli@latest build request com.example.app --platform ios --build-mode release
# Android: sign the AAB and upload to the internal track
bunx @capgo/cli@latest build request com.example.app --platform android --build-mode release --android-track internal
Logs stream into your terminal. A pre-build scan checks certificate expiry, passwords, and profile pairing before anything is uploaded, so most signing mistakes fail in seconds instead of minutes. Run it on its own with bunx @capgo/cli@latest build prescan --platform ios.
常用变体:
| 目标 | Flags |
|---|---|
| 在已注册的 iPhone 上进行测试构建 | --ios-distribution ad_hoc --ios-provisioning-profile ./adhoc.mobileprovision --output-upload |
| 用于 MDM 或 kiosk 设备的 APK | --platform android --no-playstore-upload --output-upload |
| 直接提交至 App Review | --submit-to-store-review --store-release-name 2.4.0 |
| 保留自定义构建版本号 | --skip-build-number-bump |
| 不使用缓存的全新构建 | --no-cache |
对于 ad hoc 构建,请先使用 iOS UDID 查询工具 收集设备 UDID 并将其添加到 profile 中。
在 CI 中实现签名构建自动化
在 CI 中,请将凭据作为环境变量传递,而不是使用凭据文件。CLI 导出了你所需的一切:
bunx @capgo/cli@latest build credentials manage --appId com.example.app
# choose "Export to .env"
在 GitHub 上,通过一条命令将每一行内容推送到 repository secrets,然后删除该文件:
gh secret set -f .env.capgo.com.example.app
gh secret set CAPGO_TOKEN --body "your-capgo-api-key"
rm .env.capgo.com.example.app
一个在推送 tag 时为双平台进行签名并发布的 release workflow:
name: Signed release
on:
push:
tags: ['v*']
jobs:
build:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
platform: [ios, android]
steps:
- uses: actions/checkout@v6
- uses: oven-sh/setup-bun@v2
- run: bun install --frozen-lockfile
- run: bun run build
- run: bunx cap sync ${{ matrix.platform }}
- run: bunx @capgo/cli@latest build request com.example.app --platform ${{ matrix.platform }} --build-mode release
env:
CAPGO_TOKEN: ${{ secrets.CAPGO_TOKEN }}
BUILD_CERTIFICATE_BASE64: ${{ secrets.BUILD_CERTIFICATE_BASE64 }}
P12_PASSWORD: ${{ secrets.P12_PASSWORD }}
CAPGO_IOS_PROVISIONING_MAP_BASE64: ${{ secrets.CAPGO_IOS_PROVISIONING_MAP_BASE64 }}
APPLE_KEY_ID: ${{ secrets.APPLE_KEY_ID }}
APPLE_ISSUER_ID: ${{ secrets.APPLE_ISSUER_ID }}
APPLE_KEY_CONTENT: ${{ secrets.APPLE_KEY_CONTENT }}
APP_STORE_CONNECT_TEAM_ID: ${{ secrets.APP_STORE_CONNECT_TEAM_ID }}
ANDROID_KEYSTORE_FILE: ${{ secrets.ANDROID_KEYSTORE_FILE }}
KEYSTORE_KEY_ALIAS: ${{ secrets.KEYSTORE_KEY_ALIAS }}
KEYSTORE_KEY_PASSWORD: ${{ secrets.KEYSTORE_KEY_PASSWORD }}
KEYSTORE_STORE_PASSWORD: ${{ secrets.KEYSTORE_STORE_PASSWORD }}
PLAY_CONFIG_JSON: ${{ secrets.PLAY_CONFIG_JSON }}
该任务在 Linux 上运行。无需 macOS runner,无需 keychain 命令,也无需 fastlane。相同的环境变量适用于任何 CI:GitLab CI/CD variables、Bitbucket secured variables、Gitea secrets 或 Azure DevOps variable groups。各平台的详细指南: Bitbucket Pipelines, Gitea Actions以及 GitHub Actions 文档.
密钥处理机制
在将签名密钥交给任何云服务之前,这都是一个非常合理的问题。使用 Capgo Build:
- 凭据存储在您的本地机器(
~/.capgo-credentials/)或 CI 密钥库中。Capgo 不会保存您的密钥库。 - 在每次构建时,CLI 会通过 HTTPS 发送它们。这些密钥仅在当前构建期间使用,并在构建完成后立即删除。
- 我们仅上传准备好的 native 项目。您的 Web 源码
.git,以及.env及文件不会被上传。 - 构建好的 App 会直接发送至 App Store Connect 或 Google Play,或者根据您的需求生成一个有时效性的下载链接。
权衡之处:更换凭据意味着您需要手动更新 CI secrets。重新导出并 build credentials manage 再次推送文件即可。
过期与轮换
| 项目 | 有效期 | 应对方案 |
|---|---|---|
| Apple Distribution 证书 | 1 年 | 创建新的证书,重新生成 profiles,重新保存并更新 CI |
| 描述文件 (Provisioning profile) | 1 年,或直到证书被吊销 | 重新生成并保存 |
| App Store Connect API 密钥 | 直到被吊销 | 当拥有访问权限的人员离职时吊销 |
| Android 上传 keystore | 有效期尽量长(设为数十年) | 请务必备份;若丢失,可通过 Play Console 重置 |
| Play 服务账号密钥 | 直至删除为止 | 每年轮换,或权限变更时轮换 |
把 Apple 相关日期记到共享日历里。证书过期不会影响用户设备上已有的 App,但会阻止所有新 build。
故障排除
| 错误 | 原因与修复 |
|---|---|
Provisioning profile doesn't include signing certificate |
该 Profile 是用另一个证书生成的,请用当前证书重新生成。 |
Provisioning profile doesn't match bundle ID |
该 Profile 是为另一个 App ID 创建的,或缺少 extension target。请添加一个 bundleId=path 每个目标的映射。 |
MAC verification failed |
错误 .p12 密码,或 OpenSSL 3 导出时缺少 -legacy. |
Keystore was tampered with, or password was incorrect |
Store 密码错误,或文件因 base64 换行符损坏。 |
Key alias not found |
Alias 与 keystore 中的不符。请使用以下命令列出: keytool -list -keystore release.jks. |
| App Store Connect 身份验证失败 | Key ID 或 Issuer ID 错误、密钥已撤销,或签名机器的系统时间偏差。 |
| Play 上传失败:调用者权限不足 | Service account 未在 Play Console 中受邀,或 Android Developer API 未启用。 |
更多修复方案请参阅 Capgo Build 故障排除指南 和 Capacitor 的 CI/CD:常见坑点.
完成首次签名构建后
只有在原生 code 发生变化时才需要签名 Native Build。对于 JavaScript、CSS 和 HTML 的更改,请直接推送 live update 到已安装的应用中,并将 Store 构建保留给涉及插件或原生配置的发布。如果你之前使用的是 Mac 环境, 使用 Capgo Build 在 Windows 上构建 iOS 应用 展示了无需 macOS 的完整工作流。