ほとんどの Capacitor CI/CD 失敗は、同じ少数の原因に集約されます。iOS の code 署名、macOS ツールチェーンの欠落や古さ、ネイティブプロジェクトに反映されない Web ビルド、ビルド番号の再利用、そしてアップロード時に初めて発覚するストア要件です。それぞれに既知の原因と、一度適用すれば解決する修正方法があります。本ガイドでは、パイプラインのステージごとに落とし穴を分類し、表示されるエラー、その原因、そして変更すべき点を解説します。
パイプラインをゼロから構築する場合は、まず Capacitor アプリの CI/CD セットアップ を読み、その後このリストを使って強化してください。
ステージ 1: Web レイヤーのビルド
落とし穴: ネイティブアプリが古い Web ビルドを配布している
症状: CI は成功し、アプリもインストールされますが、表示されるのは前日の UI です。
原因: cap sync は、その時点で webDir にあるものをコピーします。パイプラインが実行された場合 cap sync Webビルドの前に、またはWebビルドが別のフォルダに書き出す場合 webDir における capacitor.config.tsネイティブプロジェクトに古いファイルが混入します。
解決策: 常にこの順序でステップを実行し、出力フォルダが空の場合は失敗させます。
bun install --frozen-lockfile
bun run build
test -f dist/index.html || { echo "web build missing"; exit 1; }
bunx cap sync
必ず webDir バンドラーの出力(dist Vite の場合: www Ionic付きAngularの場合、 build 一部のReact構成の場合)。
落とし穴: 設定に開発サーバーURLが残っている
症状: リリースビルドで白画面が表示されたり、読み込みを試みたりする http://192.168.x.x:5173.
原因: server.url における capacitor.config.ts ライブリロード用に設定され、コミットされてしまった
解決策: 絶対にコミットしない server.url。CIでは設定されない環境変数から読み込む:
import type { CapacitorConfig } from '@capacitor/cli'
const config: CapacitorConfig = {
appId: 'com.example.app',
appName: 'Example',
webDir: 'dist',
...(process.env.LIVE_RELOAD_URL && {
server: { url: process.env.LIVE_RELOAD_URL, cleartext: true },
}),
}
export default config
落とし穴: 不適切なタイミングで焼き込まれる環境変数
症状: 本番アプリがステージングの API と通信してしまう
原因: Vite、webpack、Angular はビルド時に環境変数をインライン化します。その時点で存在する値が bun run build 実行されるのはバイナリ内のもの、そして同じジョブからビルドされたすべての live update です。
解決策: Web ビルド前に、ジョブごとに環境固有の変数を設定し、staging と production 用にそれぞれ別の bundle をビルドしてください。後から切り替えることはできません。 cap sync.
落とし穴: lockfile のドリフト
症状: CI 上のプラグインバージョンがローカル環境と異なり、シンボル不足でネイティブコンパイルが失敗します。
解決策: lockfile をコミットし、以下でインストールします bun install --frozen-lockfile (または npm ci)。 @capacitor/core, @capacitor/ios, @capacitor/androidや @capacitor/cli を同じバージョンに固定してください。バージョン不一致はネイティブエラーの頻繁な原因です。詳細は Capacitor バージョン不一致エラーの修正.
ステージ2: ネイティブツールチェーン
落とし穴: Node、JDK、または Xcode のバージョン違い
症状: Unsupported class file major version, The engine "node" is incompatible、または SDK 機能に関する Xcode エラー。
原因: ホスト型ランナーのイメージは変更され、Capacitor 8 には明確な最低要件があります。
| ツール | Capacitor 8 の要件 |
|---|---|
| Node.js | 22 以降 |
| JDK | 21 |
| iOSプロファイリング | 26 以降 |
| iOS デプロイメントターゲット | 15.0 |
Androidでは minSdkVersion / targetSdkVersion |
24 / 36 |
解決策: 信頼せず、パイプライン内ですべてのバージョンを明示的にピン留めする latest:
- uses: actions/setup-node@v6
with:
node-version-file: .nvmrc
- uses: actions/setup-java@v4
with:
distribution: temurin
java-version: '21'
- uses: maxim-lobanov/setup-xcode@v1
with:
xcode-version: '26'
落とし穴: Apple がもはや受け入れない Xcode でビルドする
症状: サポートされていない SDK でビルドされたというメッセージとともに、アップロードが失敗します。
原因: 2026 年 4 月 28 日以降、App Store Connect は Xcode 26 と iOS 26 SDK を必須とします。セルフホスト Mac や古いランナーイメージは、まだ Xcode 16 がデフォルトです。
解決策: 選択 macos-26 イメージ、またはランナーに Xcode 26 をインストールしてください。詳細は Appleによる Capacitor アプリ向けのXcode 26要件.
落とし穴: CocoaPods と SPM の混同
症状: xcodebuild: error: 'App.xcworkspace' does not exist、または pods が見つからない。
原因: 新しい Capacitor 8 プロジェクトは Swift Package Manager を使用し、 ios/App/App.xcodeproj をビルドします。古いプロジェクトは CocoaPods を使用し、 ios/App/App.xcworkspace その後 pod install をビルドします。古いチュートリアルからコピーしたパイプラインはワークスペースを前提としています。
解決策: プロジェクトで使用されているものを確認し、適切なファイルをビルドしてください。移行する場合は、 Capacitor アプリを SPM に移行する方法.
落とし穴: Gradle アップグレード後に Android プラグインのビルドが壊れる
症状: Namespace not specified, package attribute is deprecated、またはプラグインによるエラー build.gradle Android Studio を更新した後。
解決策: Android Gradle Plugin のバージョンを固定する android/build.gradle、ブランチでアップグレードし、先にプラグインを更新してください。具体的なエラーについては AGP 9 で Capacitor プラグインのビルドエラーを修正.
ステージ3: Code の署名
落とし穴: iOS の署名は Mac 上でしか動作しない
症状: No signing certificate "iOS Distribution" found, No profiles for 'com.example.app' were found、または errSecInternalComponent.
原因: Mac のキーチェーンには証明書が保存され、Xcode がプロファイルをダウンロードしてくれます。CI ランナーにはこれらがなく、非対話セッションではキーチェーンがロックされています。
解決策: 証明書を一時のアンロックされたキーチェーンにインポートし、Xcode 16 以降が参照する場所にプロファイルをインストールします:
security create-keychain -p "$KEYCHAIN_PASSWORD" ci.keychain
security set-keychain-settings -lut 21600 ci.keychain
security unlock-keychain -p "$KEYCHAIN_PASSWORD" ci.keychain
security import dist.p12 -k ci.keychain -P "$P12_PASSWORD" -T /usr/bin/codesign
security set-key-partition-list -S apple-tool:,apple: -s -k "$KEYCHAIN_PASSWORD" ci.keychain
security list-keychains -d user -s ci.keychain login.keychain
PROFILES="$HOME/Library/Developer/Xcode/UserData/Provisioning Profiles"
mkdir -p "$PROFILES"
cp app.mobileprovision "$PROFILES/"
アイデンティティ名を使用します Apple Distribution、レガシーの iOS Distributionではなく。fastlane の setup_ci と match がこれを自動化します。Capgo Build は証明書とプロファイルを環境変数として受け取り、独自のマシンでキーチェーンの処理を行うため、Linux ジョブは security.
落とし穴: 期限切れまたは失効した証明書
症状: 1年間安定して動いていたpipelineが、ある夜突然失敗する。
原因: Appleの配布証明書とプロビジョニングプロファイルは1年で期限切れになります。チームメンバーがXcodeで新しい証明書を作成すると、CIで使用しているプロファイルが無効になることもあります。
解決策: 期限日をチームカレンダーに記録し、CI用に共有の配布証明書を1つ維持し、ビルド前に確認しましょう。 bunx @capgo/cli@latest build prescan --platform ios アップロード前に、証明書の期限、パスワード、プロファイルの対応関係を確認します。
落とし穴: Apple IDのログインと2要素認証のprompt
症状: fastlaneが6桁のcodeを待ってハングする。
解決策: App Store ConnectのAPIキーを(.p8、キーID、イシューアID) を使用します。Apple IDとパスワードは不要です。2要素認証も不要で、App Managerにスコープを限定できます。正しいキーでも認証が失敗する場合は、ランナーの時刻を確認してください。トークンはローカル時刻で署名されており、タイムスタンプがずれているとAppleによって拒否されます。
落とし穴: デコードできない base64 シークレット
症状: MAC verification failed, invalid keystore format、または base64: invalid input.
原因: base64 値をコピーした際に改行が追加されたり、 .p12 OpenSSL 3 のデフォルト設定で作成され、macOS が読み取れないもの。
解決策: 1行でエンコードし、 -legacy を作成する際は .p12 OpenSSL 3 で:
base64 -i dist.p12 | tr -d '\n' > dist.p12.b64
openssl pkcs12 -export -legacy -inkey key.pem -in cert.pem -out dist.p12
落とし穴: 失われた Android keystore
症状: 誰もkeystoreを持っていないため、アップデートに署名できません。
解決策: Play App Signingでは、keystoreはアップロードキーであり、Play Consoleのサポートに新しいキーの登録を依頼できます。keystoreはCIのシークレットとオフラインバックアップに保存してください。1台のラップトップだけに置かないでください。 Android keystore ジェネレーター ゼロから始める場合は、新しいものを作成します。
ステージ4: パイプライン設計
落とし穴: 全プルリクエストでのネイティブビルド
症状: 遅いPRチェックと高額なmacOS分課金。
原因: ホスト型macOSランナーでのiOSビルドは、ほとんどのCIプランで最も高価な分課金ですが、多くのコミットはJavaScriptのみを変更します。
解決策: すべてのPRでlint、テスト、Webビルドを実行します。リリースタグまたはマージ時にネイティブビルドを実行します main。PRプレビューでは、バイナリをビルドする代わりに、Capgo チャネルにWebバンドルを配信します(詳細は Capacitor アプリ向け CI/CD プラットフォームの比較.
落とし穴: iOSとAndroidを順次ビルドする
解決策: マトリックスを使用し、両プラットフォームを並列でビルドし、 fail-fast: false を設定して、iOSの署名問題で正常なAndroidビルドがキャンセルされないようにします。
strategy:
fail-fast: false
matrix:
platform: [ios, android]
落とし穴: キャッシュなし、または誤ったキャッシュ
症状: すべてのビルドでGradle依存関係とCocoaPodsを最初からダウンロードするか、古いキャッシュからステージングビルドに本番設定が含まれてしまう。
解決策: キャッシュ ~/.gradle/caches, ~/.gradle/wrapperや ios/App/Pods lockfile をキーにしています。キャッシュは環境ごとに分割してください。Capgo Build では、アプリごとのビルドキャッシュを次のように分割できます --cache-key prod と --cache-key staging、または --no-cache でスキップしてクリーンビルドできます。
落とし穴: モノレポのパス
症状: could not find capacitor.config 、またはネイティブプロジェクトにプラグインがない場合。
解決策: Capacitor コマンドはアプリパッケージから実行し、ツールはホイスティングされた node_modules. Capgo CLI は次を受け付けます --path と --node-modules これについて。
ステージ5: ストアへの提出
落とし穴: ビルド番号の再利用
症状: iOSでは「バンドルバージョンは以前アップロードされたバージョンより高くする必要があります」、Google Playでは「バージョン code はすでに使用されています」というエラー。
解決策: CIで番号を生成します。fastlaneを使う場合は、最新のTestFlightビルドを読み取って1を加算します。Capgo Buildではこれがデフォルトです: App Store Connectから最新のビルド番号を取得するか、最大 versionCode Google Playから取得して増分します。
落とし穴: TestFlightでビルドが停滞
症状: アップロードは成功するが、テスターがビルドを見ることができない。
原因: エクスポートコンプライアンスの回答が不足しています。
解決策: を1か所で宣言します ios/App/App/Info.plist 標準的な暗号化のみを使用する場合:
<key>ITSAppUsesNonExemptEncryption</key>
<false/>
落とし穴: プライバシーマニフェストの拒否
症状: 必須の理由 API 宣言が不足しているという Apple からのメール (ITMS-91053)。
解決策: を追加します PrivacyInfo.xcprivacy アプリターゲットに追加し、独自のマニフェストを同梱するプラグインを更新します。詳細は iOSアプリ向けプライバシーマニフェストガイド.
落とし穴: 誤ったアーティファクトタイプ
解決策: Google PlayにはAABが必要です (bundleRelease), APK ではありません。 bundleRelease 署名設定がなくても成功してしまい、 release Play Store で拒否される未署名の AAB が生成されるので、まず signingConfigs.release における android/app/build.gradle 設定してください。iOS では、開発用や ad hoc の IPA ではなく、App Store 用のエクスポートが必要です。ビルドステップのエクスポート方法を確認してください。
ステージ 6: Live Updates
落とし穴: 新しい Native Build が必要な live update をリリースしてしまう
症状: OTAアップデート後、インストール済みのバイナリに存在しないプラグインメソッドを呼び出すため、アプリがクラッシュします。
原因: web bundle が、ユーザーのデバイス上のアプリにコンパイルされているものよりも新しいバージョンのプラグインに依存している場合に発生します。
解決策: パイプラインに判断させる。 build needed ネイティブ依存関係がチャネル上のライブ状態と一致する場合に 0 で終了し、新しいバイナリが必要な場合に 1 で終了します:
if bunx @capgo/cli@latest build needed com.example.app --channel production; then
bunx @capgo/cli@latest bundle upload com.example.app --channel production
else
bunx cap sync
bunx @capgo/cli@latest build request com.example.app --platform ios
bunx @capgo/cli@latest build request com.example.app --platform android
fi
また、以下のファイルが変更された場合もネイティブパスを強制します ios/, android/、または capacitor.config.* 。完全なパターンは live update か Native Build を自動選択にあり、互換性ルールは ネイティブ互換性.
最も多くの落とし穴を解消する修正
If you only change one thing, move iOS compilation and signing out of your CI runners. Keychain setup, Xcode upgrades, macOS costs, and profile installation all disappear from your pipeline when a Linux job hands the prepared project to Capgo のビルド:
bun install --frozen-lockfile && bun run build
bunx cap sync ios
bunx @capgo/cli@latest build request com.example.app --platform ios --build-mode release
ステージ1、5、6の落とし穴は、ランナーではなくプロジェクト自体に関わるため、引き続き適用されます。失敗したジョブのデバッグについては、こちらを参照してください。 CapacitorのCI/CDパイプラインでのビルド失敗の修正.
クイックリファレンス
| エラー | 落とし穴 | セクション |
|---|---|---|
| 新しいビルドで古いUIが表示される | cap sync Webビルドの前 |
ステージ1 |
No profiles for ... were found |
プロファイルが未インストール、または不一致 | ステージ 3 |
errSecInternalComponent |
キーチェーンがロックされている | ステージ 3 |
MAC verification failed |
パスワード誤りまたは OpenSSL 3 .p12 |
ステージ 3 |
Unsupported class file major version |
JDK が正しくない | ステージ 2 |
| アップロード時の SDK が古すぎる | Xcode が 26 より古い | ステージ 2 |
| Bundle バージョンは高い必要がある | ビルド番号の再利用 | ステージ 5 |
| バージョン code は既に使用済みです | 再利用済み versionCode |
ステージ 5 |
| live update 後のクラッシュ | ネイティブ変更の OTA 配信 | ステージ 6 |