Capacitor ビルド&開発環境(iOS 編)
Capacitor ブログシリーズについて
このシリーズでは、Web アプリをモバイルアプリ化する Framework「Capacitor」について、実際の開発で必要になる内容を順に解説していきます。
シリーズ予定:
- ✅ Capacitor ビルド&開発環境(WSL & Android 編)
- ✅ Capacitor ビルド&開発環境(iOS 編) ← 今回
- Capacitor FirebaseAppDistribution でアプリ公開
- Capacitor WebRTC で通話アプリを作りたかった
- Capacitor プッシュ通知実装してみた
- Capacitor バックグラウンドでも正しく動くようにしてみた
今回は第 2 弾として、macOS 環境での iOS アプリ開発環境構築と、CI/CD を見据えた署名なしビルドの手法を解説します。
はじめに
こんにちは!PortalKey の渋谷です。
前回の Android 編に続き、今回は iOS 編です。iOS のビルドは macOS でしか行えないため、Mac での作業となります。
この記事では、Capacitor を使った iOS アプリのビルドから、CI/CD 環境で署名なしで archive を作成し、後から署名して IPA を生成するという実践的な手法までを紹介します。
この記事でできること:
- ✅ Xcode での Capacitor iOS プロジェクトセットアップ
- ✅ コマンドラインでのビルド・archive 作成
- ✅ 署名なしで archive → 後から署名して IPA 生成(CI/CD 向け)
開発環境
今回の実装環境は以下の通りです:
必須環境:
- macOS(iOS ビルドには必須)
- Xcode(App Store からインストール)
- Apple Developer Program への登録(実機テスト・配布に必要)
前提条件:
- Capacitor が導入済み(前回の Android 編で解説)
- Web サイトがビルドできる状態
Xcode の初期設定
Capacitor 公式の iOS セットアップガイドに沿って、Xcode の初期設定を行います: 基本的には Xcode のインストールと、Command Line Tools の設定のみで完了します。
Capacitor iOS プロジェクトの初期化
プラットフォームの追加
まだ iOS プラットフォームを追加していない場合:
npx cap add ios
同期
Web アプリをビルドして iOS プロジェクトに同期:
# Webアプリのビルド
yarn build
# iOSプロジェクトへ同期
npx cap sync ios
Xcode での設定
プロジェクトを開く
npx cap open ios
Xcode が起動し、ios/App/App.xcworkspace が開きます。
Signing & Capabilities の設定
- 左側のプロジェクトナビゲータで
Appを選択 -
Signing & Capabilitiesタブを開く -
Teamに自分の Apple Developer アカウントを設定 -
Bundle Identifierを適切な値に設定(例:com.yourcompany.app)
Xcode が自動的に Provisioning Profile を管理してくれます。
権限の追加(必要に応じて)
Info.plist にアプリが使用する権限を追加します。例えば、カメラやマイクを使用する場合:
<key>NSCameraUsageDescription</key>
<string>カメラを使用します</string>
<key>NSMicrophoneUsageDescription</key>
<string>マイクを使用します</string>
コマンドラインでのビルド
ここからが本題です。CI/CD 環境を見据えて、コマンドラインでビルドを行います。
基本的なビルドコマンド
弊社では以下のようなスクリプトを package.json に定義しています:
{
"scripts": {
"ios:sync": "npx cap sync ios",
"ios:build": "yarn mobile:build --mode ios && yarn ios:sync",
"ios:open": "npx cap open ios",
"ios:run": "npx cap run ios"
}
}
実機での動作確認
開発中は cap run が便利です:
npx cap run ios
接続されている実機やシミュレータを選択して、アプリをインストール・起動できます。
CI/CD 向け:署名なしで archive を作成する
ここが今回一番伝えたいポイントです。
通常、Xcode でアプリを archive すると署名も同時に行われます。しかし、CI/CD 環境では署名なしで archive を作成し、後から署名して IPA を生成するという 2 段階のアプローチが有効です。
なぜ署名なしで archive するのか
一般的なメリットとして:
- CI 環境でビルドマシンと署名を分離できる
- 同じ archive から複数の署名(Ad-hoc, App Store)で IPA を生成できる
- 証明書の管理が柔軟になる
しかし、弊社がこの方法を採用した本当の理由は別にあります。
⚠️ 「○○ をインストールできません」問題
結論から言うと、archive 時に署名してしまうと、export 時の署名と不整合が起き、アプリがインストールできなくなるケースがあります。
実際に弊社でもこの問題に遭遇し、以下のエラーがずっと出続けました:
「PortalKeyをインストールできません」
原因究明にかなりの時間を費やしましたが、原因は archive 時の署名と export 時の署名の不一致でした:
【問題のフロー】
archive(Profile A で署名)
→ export(Profile B を指定して IPA 生成)
→ 署名の不整合が発生
→ 「インストールできません」
【解決したフロー】
archive(署名なし)
→ export(Profile B で初めて署名)
→ 整合性 OK
→ 正常にインストール・起動できる
署名なしで archive すれば、export 時に初めて署名が適用されるため、Profile と署名が確実に一致します。
archive コマンド
以下のように CODE_SIGNING_REQUIRED と CODE_SIGNING_ALLOWED を NO にして実行すると、署名なしの archive が生成できます。
cd ios/App
# バージョン番号を更新(オプション)
agvtool new-version $(date "+%Y.%m%d.%H%M")
# 署名なしでarchive
xcodebuild \
-workspace App.xcworkspace \
-scheme App \
-configuration Release \
CODE_SIGNING_REQUIRED=NO \
CODE_SIGNING_ALLOWED=NO \
-archivePath ../dist/build/App.xcarchive \
clean archive
ポイント:
-
CODE_SIGNING_REQUIRED=NO- 署名を必須としない -
CODE_SIGNING_ALLOWED=NO- 署名を許可しない - これにより、署名なしの
.xcarchiveが生成される
ExportOptions.plist の準備
IPA を生成するには ExportOptions.plist が必要です。
このファイルは手書きするより、一度 Xcode の GUI で archive → Export を実行し、生成された plist をコピーして使うのが確実です。その例がこちらです:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>destination</key>
<string>export</string>
<key>method</key>
<string>release-testing</string>
<key>signingStyle</key>
<string>automatic</string>
<key>stripSwiftSymbols</key>
<true/>
<key>teamID</key>
<string>YOUR_TEAM_ID</string>
<key>thinning</key>
<string><none></string>
</dict>
</plist>
IPA の生成(署名付き)
cd ios/App
xcodebuild \
-exportArchive \
-archivePath ../dist/build/App.xcarchive \
-exportPath ../dist/build \
-exportOptionsPlist ExportOptions.plist \
CODE_SIGN_STYLE=Automatic \
PRODUCT_BUNDLE_IDENTIFIER=com.yourcompany.app \
-allowProvisioningUpdates \
-authenticationKeyIssuerID YOUR_ISSUER_ID \
-authenticationKeyID YOUR_KEY_ID \
-authenticationKeyPath /path/to/AuthKey.p8
オプションの説明
基本オプション:
| オプション | 説明 |
|---|---|
-archivePath |
入力する archive のパス |
-exportPath |
IPA の出力先ディレクトリ |
-exportOptionsPlist |
Export 設定ファイル(署名方法やチーム ID など) |
署名関連オプション:
| オプション | 説明 |
|---|---|
CODE_SIGN_STYLE=Automatic |
Xcode に自動で署名させる |
PRODUCT_BUNDLE_IDENTIFIER |
Bundle ID を明示的に指定(複数環境ある場合に便利) |
-allowProvisioningUpdates |
Provisioning Profile を自動で取得・更新する |
App Store Connect API 認証オプション:
| オプション | 説明 |
|---|---|
-authenticationKeyIssuerID |
API Key の Issuer ID(UUID 形式) |
-authenticationKeyID |
API Key の Key ID(10 文字程度) |
-authenticationKeyPath |
API Key ファイル(.p8)のパス |
認証キーが必要な理由
-allowProvisioningUpdates を使うと、xcodebuild が App Store Connect に接続して Provisioning Profile を取得・更新します。
- GUI で Xcode を使う場合 → Apple ID でログイン済みなので認証キー不要
- CI 環境(ヘッドレス) → ログインできないので、API Key での認証が必須
API Key の取得方法
- App Store Connect にログイン
-
Users and Access→Keysタブを開く - 「+」ボタンで新しいキーを生成
- 以下の情報をメモ:
- Issuer ID - ページ上部に表示される UUID
- Key ID - 生成したキーの横に表示される ID
- AuthKey_XXXXX.p8 - ダウンロード(一度しかダウンロードできないので注意!)
全体の流れをスクリプト化
弊社の package.json では以下のように定義しています:
{
"scripts": {
"ios:archive": "cd ios/App && agvtool new-version $(date \"+%Y.%m%d.%H%M\") && xcodebuild -workspace App.xcworkspace -scheme App -configuration Release CODE_SIGNING_REQUIRED=NO CODE_SIGNING_ALLOWED=NO -archivePath ../dist/build/App.xcarchive clean archive",
"ios:build:ipa": "yarn ios:build && yarn ios:archive && cd ios/App && xcodebuild -exportArchive -archivePath ../dist/build/App.xcarchive -exportPath ../dist/build -exportOptionsPlist ExportOptions.plist CODE_SIGN_STYLE=Automatic PRODUCT_BUNDLE_IDENTIFIER=com.yourcompany.app -allowProvisioningUpdates -authenticationKeyIssuerID $ISSUER_ID -authenticationKeyID $KEY_ID -authenticationKeyPath $KEY_PATH"
}
}
デバッグ環境
Xcode のコンソール
ネイティブ側のログは Xcode のコンソールで確認できます。アプリを Xcode から実行するか、Window → Devices and Simulators からデバイスを選択してログを確認します。
⚠️ よくあるトラブル
CORS エラー
Android 編と同様、capacitor://localhost を AllowedOrigins に追加してください。
Provisioning Profile のエラー
CODE_SIGN_STYLE=Automatic を使用している場合、Apple Developer アカウントでの認証が必要です。CI 環境では App Store Connect API キーを使用します。
Pod install が必要
npx cap sync ios を実行すると自動的に pod install も行われますが、エラーが発生した場合は手動で実行してみてください:
cd ios/App
pod install
まとめ
iOS 環境でも Capacitor を使ったアプリ開発は比較的スムーズに行えます。
今回実装したのは:
- ✅ Xcode での Capacitor iOS セットアップ
- ✅ コマンドラインでのビルド・archive
- ✅ 署名なし archive → 後から署名して IPA 生成
特に「インストールできません」問題を回避するためにも、署名なしで archive を作成するアプローチは有効です。同じ問題でハマっている方の参考になれば幸いです。
次回は Firebase App Distribution を使ったアプリ配布について解説予定です!
Discussion