跳转至正文

如何在云端签名并构建 Capacitor App

在云端为您的 Capacitor 应用签名并构建:创建 Android keystore 和 iOS 证书,安全存储凭据,并在 CI 中运行签名构建。

在云端构建中用于为 Capacitor 应用进行签名的 iOS 证书和 Android keystore

若要在云端对 Capacitor 应用进行签名和构建,您只需一次性准备好签名材料(Android keystore、iOS 分发证书及 provisioning profile),将其提供给云构建服务,然后通过终端或 CI 触发构建即可。该服务会编译原生项目、进行签名,并能直接将其 upload 到 TestFlight 或 Google Play。本指南将涵盖每种签名文件、如何在没有 Mac 的情况下创建它们、如何通过 Capgo Build 进行配置,以及如何安全地实现签名构建自动化。

“云端签名”是什么意思

两个应用商店都只接受已签名的二进制文件。签名可以证明该 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 号

别把这些放进 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 会持有 应用签名密钥 并重新签名用户下载的内容。你的 keystore 就是 上传密钥。如果丢失了它,Play Console 支持团队可以注册新的上传密钥,所以丢失只会造成延迟,而不是灾难。不过还是要备份。

用于上传的服务账号

若要从云端上传,请在 Google Cloud 中创建一个服务账号,启用 Google Play Android Developer API,下载其 JSON 密钥,然后在 Play Console 的 用户和权限 中邀请该服务账号,并授予该服务账号针对你应用的发布权限。如下所示,Capgo 的 onboarding 可以通过 Google 登录完成此操作。

iOS 签名

Apple 签名的三个要素

  • Apple Distribution 证书。 每个团队一个就够了,有效期一年。Apple 对证书数量有限制,所以不要给每个开发者都创建一个。
  • 描述文件。 将 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
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

对于带有 extension 的应用,请重复上述步骤 --ios-provisioning-profile 凭借 bundleId=path 每个目标的映射关系:

  --ios-provisioning-profile com.example.app=./App.mobileprovision \
  --ios-provisioning-profile com.example.app.widget=./Widget.mobileprovision

凭据存储在 ~/.capgo-credentials/credentials.json,以 app ID 和平台作为键。添加 --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

日志会流式输出到你的终端。构建前扫描会在上传任何内容之前检查证书有效期、密码和 profile 配对,因此大多数签名错误会在几秒内失败,而不是等上几分钟。也可以单独运行: bunx @capgo/cli@latest build prescan --platform ios.

常用变体:

目标 参数
在已注册的 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 构建,请先用以下工具收集设备 UDID: iOS 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 }}

该 job 在 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 发送它们。它们只在该次构建期间使用,构建完成后即删除。
  • 只会上传准备好的原生项目。你的 Web 源码 .git,以及 .env 文件不会上传。
  • 构建好的 App 会直接发到 App Store Connect 或 Google Play,或者按你的要求提供限时下载链接。

权衡是:轮换凭据意味着你需要自己更新 CI secrets。使用 build credentials manage 重新导出,然后再次 push 文件即可。

过期与轮换

项目 累计时长 处理方式
Apple Distribution 证书 1 年 创建新证书,重新生成 profiles,重新保存并更新 CI
描述文件 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 upload 失败:调用者权限不足 未在 Play Console 中邀请服务账号,或未启用 Android Developer API。

更多解决方案请参阅 Capgo Build 故障排除指南 以及 Capacitor 的 CI/CD:常见坑点.

完成首次签名构建后

只有在涉及原生 code 变更时才需要签名 Native Build。对于 JS、CSS 和 HTML 的变更,请直接推送 live update 到已安装的应用中,并将 Store Build 保留给涉及插件或原生配置的发布。如果你之前使用 Mac 环境, 使用 Capgo Build 在 Windows 上构建 iOS 应用 展示了无需 macOS 的完整工作流。

为 Capacitor 应用提供 Live Updates

当 Web 层出现线上 Bug 时,通过 Capgo 发布修复,而不用等 App Store 审核好几天。用户会在后台收到更新,原生变更则仍走正常审核流程。

博客最新动态

Capgo 为你提供打造真正专业的移动应用所需的最有价值的洞察。