📲

Capacitor ビルド&開発環境(iOS 編)

に公開

Capacitor ブログシリーズについて

このシリーズでは、Web アプリをモバイルアプリ化する Framework「Capacitor」について、実際の開発で必要になる内容を順に解説していきます。

シリーズ予定:

  1. ✅ Capacitor ビルド&開発環境(WSL & Android 編)
  2. Capacitor ビルド&開発環境(iOS 編) ← 今回
  3. Capacitor FirebaseAppDistribution でアプリ公開
  4. Capacitor WebRTC で通話アプリを作りたかった
  5. Capacitor プッシュ通知実装してみた
  6. 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 の初期設定を行います:
https://capacitorjs.jp/docs/getting-started/environment-setup#ios-requirements
基本的には 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 の設定

  1. 左側のプロジェクトナビゲータで App を選択
  2. Signing & Capabilities タブを開く
  3. Team に自分の Apple Developer アカウントを設定
  4. 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_REQUIREDCODE_SIGNING_ALLOWEDNO にして実行すると、署名なしの 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>&lt;none&gt;</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 の取得方法

  1. App Store Connect にログイン
  2. Users and AccessKeys タブを開く
  3. 「+」ボタンで新しいキーを生成
  4. 以下の情報をメモ:
    • 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 を使ったアプリ配布について解説予定です!

参考リンク

PortalKey Tech Blog

Discussion