メインコンテンツへスキップ
CI/CD

証明書付き GitHub actions による Capacitor iOS 自動ビルド

fastlaneとGitHub Actionsを使って、Ionic iOSアプリのCI/CDパイプラインを5分で構築する方法 (2024年版)

証明書付き GitHub actions による Capacitor iOS 自動ビルド

Capacitor アプリの CI/CD セットアップは複雑で、時間もかかりがちです。押さえておきたいポイントは次のとおりです:

現在は以下を使用することを推奨しています: Capgo CLI を使用した Capgo Build ネイティブ Capacitor ビルド用。 このFastlaneガイドは、既存の GitHub Actionsパイプラインを保守するチーム向けに残しています。ただし、新規のiOSビルドには、Fastlane、Xcodeランナー、証明書、アップロードスクリプトを自分で保守しなくて済む Capgo CLI の使用を推奨します。

Capgo によるCI/CD向けCapgo Build

Fastlane、Xcodeランナー、証明書、プロビジョニングプロファイル、アップロードスクリプトのメンテナンスを不要に。 Capgo のビルド 既存のCI/CDパイプラインから、署名済みのネイティブiOSビルドを実行します:

  • パイプラインと連携: Webビルド後に、GitHub Actions、GitLab CI、Jenkins、またはローカルスクリプトから Capgo Build をトリガーし、 npx cap sync.
  • CIシークレットで署名: App Store Connectのキー、証明書、プロビジョニングプロファイル、パスワード、チームIDは、自分のCIシークレットに保管します。
  • ネイティブランナーの運用不要: Capgo Buildはメンテナンス済みのAppleビルド環境を提供するため、macOSランナー、Xcodeイメージ、Fastlaneレーンを管理する必要はありません。
  • アーティファクトと提出: QA用の署名済みアーティファクトをダウンロードするか、Capgo CLI からリリースビルドを提出できます。

料金プラン

  • Capgo プランは月額$12から
  • OTAアップデートと月間約15回のNative Buildを含む
  • 追加のビルド時間はクレジットで分単位課金されます

CI/CDでCapgo Buildをセットアップする

手動セットアップガイド

手順は以下の通りです:

FastlaneとGitHub Actions、および証明書を使用したiOSの継続的デリバリー

前提条件

チュートリアルを進める前に:

  • Fastlaneが インストール されていることを確認してください。
  • iOS Developer Programに加入していることを確認してください。

料金に関する重要な情報

GitHub Actionの料金

https://github.com/features/actions

本サービスは「無料」 ですが、選択したマシンによって上限があります。
今回は macOS マシンについて、スクリーンショットで価格と制限を確認できます(価格はチュートリアル作成時点のものであり、将来変更される可能性があります)。

要件と価格を確認したところで、先に進みましょう。

注意:この記事では、App Store Connect でアプリが作成済みであることを前提としています。重要な情報は Fastlane によってコピーされます。

このチュートリアルで学べること

この記事の手順

  1. Fastlane を使用した App Store Connect API の利用
    • 要件:
      • App Store Connect API キーの作成
      • App Store Connect API キーの使用
  2. Fastlane ファイルのコピー
  3. GitHub Actions の設定

1. Fastlane を使用した App Store Connect API の利用

2021年2月より、App Store Connectへのサインインには、すべてのユーザーに対して2要素認証または2段階認証が必須となりました。Apple IDにこのセキュリティレイヤーを追加することで、アカウントへのアクセスを本人だけに限定できます。
から Appleサポート

要件

FastlaneがApp Store Connect API を使用してアプリをアップロードできるようにするには、以下の 3つ の準備が必要です:

  1. Issuer ID
  2. Key ID
  3. KeyファイルまたはKeyの内容

App Store Connect API Keyの取得方法

キーを生成するには、App Store ConnectのAdmin権限が必要です。権限をお持ちでない場合は、担当者にこちらの記事を共有してください。

  1. にログイン App Store Connect.

  2. 選択します ユーザとアクセス.

App Store Connect のユーザアクセス

3 — 「統合」タブを選択します。

App Store Connect API 統合

  1. API キーを生成、または「追加 (+)」ボタンをクリックします。

App Store Connect API キーの作成

  1. キーの名前を入力します。この名前は管理用であり、キー自体の一部ではありません。

App Store Connect API キー作成名

6 — 「アクセス」で、キーのロールを選択します。キーに適用されるロールは、チームのユーザに適用されるものと同じです。詳細は ロール権限. 以下を選択することを推奨します アプリマネージャー.

  1. Generateをクリックします。

API キーのアクセス権限は、特定のアプリのみに制限することはできません。

新しいキーの名前、キーID、ダウンロードリンク、その他の情報がページに表示されます。

App Store Connect のダウンロードキー

必要な3つの情報をここで取得できます。
<1> Issue ID (APPLE_ISSUER_ID secret
<2> Key ID (APPLE_KEY_ID secret
<3> “Download API Key” をクリックして、API の秘密鍵をダウンロードしてください。ダウンロードリンクは、秘密鍵がまだダウンロードされていない場合にのみ表示されます。Apple は秘密鍵のコピーを保持しません。そのため、ダウンロードできるのは一度だけです。

🔴 秘密鍵は安全な場所に保管してください。キーを他人と共有したり、code リポジトリに保存したり、クライアント側の code に含めたりしないでください。

App Store Connect API Key の使用

認証用の JWT トークンを作成するには、API Key ファイル(ダウンロードした p8 ファイル)、Key ID、および Issuer ID が必要です。これらの情報を Fastlane に渡す方法はいくつかありますが、ここでは Fastlane の新しい action を使う方法を選びました。 app_store_connect_api_key. その他の方法については Fastlane のドキュメントで確認できます。環境変数を設定できる一般的な CI で扱うには、この方法が一番簡単だと思うので紹介しています。

ダウンロードした p8 ファイルを Base64 に変換し、secret として保存してください(APPLE_KEY_CONTENT).

base64 -i APPLE_KEY_CONTENT.p8 | pbcopy

これで、API キーを使って Fastlane で App Store Connect を管理できるようになりました。最高!

2. 証明書

Xcode を開き、以下へ移動します 設定 > アカウント > Apple ID > チーム チームを選択します。

Code の署名ID

次をクリックします: 証明書の管理.

証明書をまだ作成していない場合は、新しく作成できます。

次をクリックします: + を選択し、 Apple Distribution

Apple Distribution

次に、証明書をダウンロードするためにKeychain Accessを開きます。 .p12 ファイル。

Keychain Accessを開き、 ログイン キーチェーンを選択し、次に 証明書.

証明書

タブから、ダウンロードしたい証明書を選択します(作成日で探すとスムーズです)。

証明書の秘密鍵を右クリックして、 エクスポート.

ファイル形式を選択 個人情報交換 (.p12).

証明書が次の形式でダウンロードされます: .p12 ファイル。

ターミナルでファイルを開き、以下のコマンドを使用してBase64に変換してください:

base64 -i BUILD_CERTIFICATE.p12 | pbcopy

これがあなたの BUILD_CERTIFICATE_BASE64 secretになります。また、入力を求められたら証明書のパスワードを入力してください。このパスワードが P12_PASSWORD secretになります。

3. プロビジョニングプロファイル

開く Apple Developer 適切なチームを選択します。

次に、以下をクリックして新しいプロファイルを作成します。 +

新しいプロファイルを作成

そして、以下を選択します。 App Store Connect.

App Store Connectを選択

次に、正しいアプリを選択してください。ワイルドカードを使用すると署名に失敗するため、注意が必要です。

正しいアプリを選択

以前に作成した正しい証明書を選択し(有効期限が今日と同じ日付・月であることを確認してください)、以下をクリックします。 Continue.

正しい証明書を選択

最後に、プロファイルの名前を入力して以下をクリックします。 生成.

この名前は、Fastlaneにおいて以下の値としてプロファイルを識別するために使用されます: APPLE_PROFILE_NAME.

プロファイルを生成

プロファイルを以下としてダウンロードできます: .mobileprovision ファイル。

プロファイルをダウンロード

プロファイルをBase64に変換し、secretとして保存してください(BUILD_PROVISION_PROFILE_BASE64).

base64 -i BUILD_PROVISION_PROFILE.mobileprovision | pbcopy

4. Fastlaneファイルをコピー

Fastlaneは、モバイル開発における一般的なタスクを自動化するために作成されたRubyライブラリです。Fastlaneを使用すると、通常Android Studioで行う一連のタスクをまとめたカスタムな「lane」を構成できます。Fastlaneでできることは多岐にわたりますが、このチュートリアルでは、いくつかのコアなactionのみを使用します。

Capacitor/IonicプロジェクトのルートにFastlaneフォルダを作成し、そこにFastfileを追加してください:

  • フォルダ: <project-root>/fastlane/
  • ファイル: <project-root>/fastlane/Fastfile

これは〜と同じ階層です package.json, capacitor.config.*、および ios/ フォルダ。〜の中に作成しないでください ios/App/.

platform :ios do
  desc 'Export ipa and submit to TestFlight'
  lane :beta do
    keychain_info = { keychain_name: "ios-build-#{Time.now.to_i}.keychain", keychain_password: SecureRandom.uuid }
    
    begin
      setup_signing(keychain_info)
      bump_build_number
      build_app_with_signing(keychain_info)
      submit_to_testflight
    ensure
      cleanup_keychain(keychain_info)
    end
  end

  private_lane :setup_signing do |options|
    create_keychain(
      name: options[:keychain_name],
      password: options[:keychain_password],
      unlock: true,
      timeout: 0,
      lock_when_sleeps: false, 
      add_to_search_list: true
    )
    import_cert(options)
    install_profile
    update_project_settings
  end

  lane :bump_build_number do
		file = File.read('../package.json')
		data_hash = JSON.parse(file)
		api_key = app_store_connect_api_key(
      key_id: ENV['APPLE_KEY_ID'],
      issuer_id: ENV['APPLE_ISSUER_ID'],
      key_content: ENV['APPLE_KEY_CONTENT'],
      is_key_content_base64: true,
      duration: 1200,
      in_house: false
    )
		build_num = app_store_build_number(
      api_key: api_key,
			app_identifier: ENV['BUNDLE_IDENTIFIER'],
			live: false
    )
		build_num = build_num + 1
		UI.message("Bumped build number to #{build_num}")
		increment_build_number(
			build_number: build_num,
			xcodeproj: "./ios/App/App.xcodeproj",
			skip_info_plist: true
		)
	end

  private_lane :import_cert do |options|
    cert_path = "#{Dir.tmpdir}/build_certificate.p12"
    File.write(cert_path, Base64.decode64(ENV['BUILD_CERTIFICATE_BASE64']))
    import_certificate(
      certificate_path: cert_path,
      certificate_password: ENV['P12_PASSWORD'] || "",
      keychain_name: options[:keychain_name],
      keychain_password: options[:keychain_password],
      log_output: true
    )
    File.delete(cert_path)
  end  
  
  private_lane :cleanup_keychain do |options|
    delete_keychain(
      name: options[:keychain_name]
    )
  end  

  private_lane :install_profile do
    profile_path = "#{Dir.tmpdir}/build_pp.mobileprovision"
    File.write(profile_path, Base64.decode64(ENV['BUILD_PROVISION_PROFILE_BASE64']))
    UI.user_error!("Failed to create provisioning profile at #{profile_path}") unless File.exist?(profile_path)
    ENV['PROVISIONING_PROFILE_PATH'] = profile_path
    install_provisioning_profile(path: profile_path)
    File.delete(profile_path)
  end

  private_lane :update_project_settings do
    update_code_signing_settings(
      use_automatic_signing: false,
      path: "./ios/App/App.xcodeproj",
      code_sign_identity: "iPhone Distribution",
      profile_name: ENV['APPLE_PROFILE_NAME'],
      bundle_identifier: ENV['BUNDLE_IDENTIFIER'],
      team_id: ENV['APP_STORE_CONNECT_TEAM_ID']
    )
    update_project_team(
      path: "./ios/App/App.xcodeproj",
      teamid: ENV['APP_STORE_CONNECT_TEAM_ID']
    )
  end

  private_lane :build_app_with_signing do |options|
    unlock_keychain(
      path: options[:keychain_name],
      password: options[:keychain_password],
      set_default: false
    )
    build_app(
      workspace: "./ios/App/App.xcworkspace",
      scheme: "App",
      configuration: "Release",
      export_method: "app-store",
      output_name: "App.ipa",
      export_options: {
        provisioningProfiles: {
          ENV['BUNDLE_IDENTIFIER'] => ENV['APPLE_PROFILE_NAME']
        }
      },
      xcargs: "-verbose",
      buildlog_path: "./build_logs",
      export_xcargs: "-allowProvisioningUpdates",
    )
  end   

  private_lane :submit_to_testflight do
    api_key = app_store_connect_api_key(
      key_id: ENV['APPLE_KEY_ID'],
      issuer_id: ENV['APPLE_ISSUER_ID'],
      key_content: ENV['APPLE_KEY_CONTENT'],
      is_key_content_base64: true,
      duration: 1200,
      in_house: false
    )
    pilot(
      api_key: api_key,
      skip_waiting_for_build_processing: true,
      skip_submission: true,
      distribute_external: false,
      notify_external_testers: false,
      ipa: "./App.ipa"
    )
  end
end

5. シークレットの設定

GitHub Actionsでは、次のステップで設定するリポジトリのシークレットを使用します。ローカルの .env ファイルは、自身のマシンからFastlaneを実行またはテストしたい場合にのみ必要です。

ローカルテスト用に、 <project-root>/fastlane/.env の隣に Fastfileを作成してください。このファイルはコミットしないでください。 fastlane/.env を .gitignore に追加するか、(既に無視されているか確認してください)。例は以下の通りです:

APP_STORE_CONNECT_TEAM_ID=UVTJ336J2D
BUNDLE_IDENTIFIER=ee.forgr.testfastlane
# See previous section for these secrets
BUILD_CERTIFICATE_BASE64=
BUILD_PROVISION_PROFILE_BASE64=
APPLE_KEY_ID=
APPLE_ISSUER_ID=
APPLE_KEY_CONTENT=
P12_PASSWORD=
APPLE_PROFILE_NAME=

APP_STORE_CONNECT_TEAM_IDの取得方法

以下に移動します: デベロッパーセンター までスクロールし、 Membership details セクション。 Team ID に設定する値は、 APP_STORE_CONNECT_TEAM_ID secret です。

app-store-connect-team-id

BUNDLE_IDENTIFIER の取得方法

  1. Xcode を開く
  2. をダブルクリックし、 App プロジェクトナビゲーターで
  3. 次に、タブをクリックします Signing and Capabilities
  4. 以下の値をコピーしてください: Bundle identifier。この値を BUNDLE_IDENTIFIER secret です。
bundle-identifier-xcode

6. ビルド処理

GitHub Actionsでは、 CI/CDワークフローの実行に 使用した分量(分単位)に基づいて課金されます。私の経験では、App Store Connectでビルドが処理されるまで、約10〜15分かかります。

プライベートプロジェクトの場合、1ビルドあたりの推定コストは最大で $0.08/分 x 15 分 = $1.2に達することもあります。これはプロジェクトの設定や依存関係によって異なります。

プライベートプロジェクトのコストが気になる場合は、以下を設定できます: skip_waiting_for_build_processing まで true. これにより、App Store Connect のビルド処理完了を待つ必要がなくなり、ビルド時間を節約できます。

ただし、トレードオフもあります。ユーザーにビルドを配信する前に、App Store Connect でアプリのコンプライアンス情報を手動で更新する必要があります。

この最適化は、主にビルド時間にコストがかかるプライベートプロジェクトで有効です。パブリック/無料プロジェクトではビルド時間は無料なため、この設定を有効にする必要はありません。詳細は GitHub の 料金ページ をご確認ください。

7. GitHub Actions のセットアップ

GitHub secrets の設定

以下の .env ファイルから secrets をコピーし、GitHub リポジトリの secrets に貼り付けてください。

以下に移動します: 設定 &gt; Secrets と Variables &gt; アクション &gt; 新規リポジトリ Secret

github-secrets

2. BUILD_CERTIFICATE_BASE64 - Base64 エンコードされた証明書

3. BUILD_PROVISION_PROFILE_BASE64 - Base64 エンコードされたプロビジョニングプロファイル

4. BUNDLE_IDENTIFIER - アプリの Bundle Identifier

5. APPLE_KEY_ID — App Store Connect API Key 🔺Key ID

6. APPLE_ISSUER_ID — App Store Connect API Key 🔺Issuer ID

7. APPLE_KEY_CONTENT — App Store Connect API Key 🔺 キーの内容: .p8, 確認してください

8. GitHub ワークフローファイルの構成

GitHub ワークフローディレクトリを作成します。

cd .github/workflows

その workflow フォルダ内に、以下の名前のファイルを作成し、 build-upload-ios.yml内容を追記してください。

name: Build source code on ios

on:
  push:
    tags:
      - '*'

jobs:
  build_ios:
    runs-on: macOS-latest
    steps:
      - uses: actions/checkout@v6
      - name: Set Node.js
        uses: actions/setup-node@v6
        with:
          node-version: 24
          cache: npm
      - name: Install dependencies
        id: install_code
        run: npm ci
      - name: Build
        id: build_code
        run: npm run build
      - uses: actions/cache@v5
        with:
          path: ios/App/Pods
          key: ${{ runner.os }}-pods-${{ hashFiles('**/Podfile.lock') }}
          restore-keys: |
            ${{ runner.os }}-pods-
      - name: Sync
        id: sync_code
        run: npx cap sync
      - uses: ruby/setup-ruby@v1
        with:
          ruby-version: '3.0'
          bundler-cache: true
      - uses: maierj/fastlane-action@v3.1.0
        env:
          APP_STORE_CONNECT_TEAM_ID: ${{ secrets.APP_STORE_CONNECT_TEAM_ID }}
          BUNDLE_IDENTIFIER: ${{ secrets.BUNDLE_IDENTIFIER }}
          BUILD_CERTIFICATE_BASE64: ${{ secrets.BUILD_CERTIFICATE_BASE64 }}
          BUILD_PROVISION_PROFILE_BASE64: ${{ secrets.BUILD_PROVISION_PROFILE_BASE64 }}
          APPLE_KEY_ID: ${{ secrets.APPLE_KEY_ID }}
          APPLE_ISSUER_ID: ${{ secrets.APPLE_ISSUER_ID }}
          APPLE_KEY_CONTENT: ${{ secrets.APPLE_KEY_CONTENT }}
          P12_PASSWORD: ${{ secrets.P12_PASSWORD }}
          APPLE_PROFILE_NAME: ${{ secrets.APPLE_PROFILE_NAME }}
        with:
          lane: ios beta
      - name: Upload release bundle
        uses: actions/upload-artifact@v6
        with:
          name: ios-release
          path: ./App.ipa
          retention-days: 10

このワークフローは、各 GitHub tagの後に実行されるようにします。tagの自動化が必要な場合は、 GitHub actions を使用した自動ビルドとリリース を参照してください してください。

このワークフローによってNodeJSの依存関係がプル・インストールされ、JavaScriptアプリのビルドが行われます。

新しいコミットを送信するたびに、TestFlight向けにリリースがビルドされます。

アプリにIonicを使用する必要はありません。Capacitorベースさえあれば動作します。古いCordovaモジュールが含まれていても問題ありませんが、Capacitor JSプラグインの使用を推奨します。

8. ワークフローを実行する

コミットを作成

コミットを 作成すると、リポジトリ内で実行中のワークフローを確認できます。

ワークフローをトリガーする

ブランチに新しいコミットをプッシュして main または development ワークフローをトリガーします。

コミットから開始

数分後、App Store Connectのダッシュボードでビルドが利用可能になります。

TestFlight ダッシュボード

9. ローカルマシンからデプロイできますか?

はい、できます。しかもとても簡単です。

従来通り、Xcodeを使用してアプリのビルドと署名が可能です。

CI/CD セットアップガイド

その他のCI/CDプラットフォーム

Live Updatesとデプロイ

感謝

この記事は以下の記事に基づいています:

次へ:GitHub アクションを使用した自動 Capacitor iOS build(証明書あり)

使用している場合 証明書付き GitHub actions による Capacitor iOS 自動ビルド CI/CD自動化を計画するには、次と連携してください Capgo CI/CD Capgo CI/CDでのプロダクトワークフローについては、 Capgo Native Build Capgo Native Buildsでのプロダクトワークフローについては、 Capgo インテグレーション Capgo インテグレーションでのプロダクトワークフロー向けに、 CI/CD 連携 CI/CD Integrationの実装詳細については、 GitHub Actions 連携 GitHub Actions Integrationの実装詳細については。

Capacitor アプリ向けの Live Updates

Web レイヤーのバグが本番で発生したら、App Store の審査を何日も待たずに Capgo で修正を配信しましょう。ネイティブの変更は通常の審査フローに残したまま、ユーザーはバックグラウンドでアップデートを受け取れます。

最新のブログ記事

Capgoは、真にプロフェッショナルなモバイルアプリを作るために必要な最高のインサイトを提供します。