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

match を使用した GitHub actions による Capacitor iOS ビルドの自動化

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

match を使用した GitHub Actions による Capacitor iOS ビルドの自動化 Capgo ブログ イラスト

Matchを使用したGitHub ActionsによるiOSビルドの自動化

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

現在は以下を使用することを推奨しています: Capgo CLI を使用した Capgo Build ネイティブ Capacitor ビルド用。 このFastlane Matchガイドは、既存のGitHub Actionsパイプラインを維持しているチーム向けに残しています。ただし、新規のiOSビルドではCapgo CLIを使うべきです。Fastlane、Matchリポジトリ、Xcodeランナー、証明書、アップロードスクリプトを自分で管理する必要はありません。

Capgo によるCI/CD向けCapgo Build

Fastlane Match、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、Matchリポジトリを管理する必要はありません。
  • アーティファクトと提出: QA用の署名済みアーティファクトをダウンロードするか、Capgo CLI からリリースビルドを提出できます。

料金プラン

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

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

手動セットアップガイド

手順は以下の通りです:

Fastlaneとmatchを使ったGitHub ActionsによるiOSの継続的デリバリー

前提条件

チュートリアルを続ける前に…

  • Fastlaneが インストール されていることを確認してください。
  • iOS Developer Programへの登録
  • 読みたくなる 😆…
  • 開発者が多いチーム向け。それ以外は fastlane cert をよりシンプルなワークフローに使うのがおすすめです。

料金に関する重要事項

GitHub Actionの料金

https://github.com/features/actions

サービスは、選択したマシンに応じて、制限内であれば「無料」で利用できます。
今回は macOS マシンの価格と制限はスクリーンショットで確認できます(価格はチュートリアル作成時点のもので、今後変更される可能性があります)。

🔴 要件と価格を確認したところで、続けましょう…

📣 この記事では、iTunes Connect でアプリが作成済みで、Apple エコシステムの証明書も揃っているものとします。すべて Fastlane がコピーします!

詳しく見ていきましょう 🤿

この記事の手順

  1. Fastlane Match で App Store Connect API を使う
  2. 要件
  3. App Store Connect API Keyの作成
  4. App Store Connect API Key の使用
  5. Fastlaneファイルをコピー
  6. Fastlane matchを設定

1. Fastlane MatchでApp Store Connect APIを使用する

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

matchを使い始めるには、既存の証明書を失効させる必要があります。でも心配いりません。新しい証明書はすぐに取得できます。

要件

App Store Connect API を使用するには、Fastlaneには 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 — Integrationタブを選択します。

App Store Connect API 連携

4 — Generate API Key、または追加 (+) ボタンをクリックします。

App Store Connect API キーの作成

5 — キーの名前を入力します。この名前は参照用であり、キー自体の一部ではありません。

App Store Connect API キー作成時の名前

6 — Access でキーのロールを選択します。キーに適用されるロールは、チーム内のユーザーに適用されるロールと同じです。詳細は ロールの権限 を参照してください。次を選択することを推奨します: アプリマネージャー.

7 — Generate をクリックします。

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

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

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

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

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

App Store Connect API Key の使用

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

これで App Store Connect の API キーを使って Fastlane を管理できます。素晴らしいですね!

2. Fastlaneファイルをコピー

Fastlane は、モバイル開発でよくあるタスクを自動化するために作られた Ruby ライブラリです。Fastlane を使うと、通常 Android Studio で行うタスクを実行する一連の「アクション」をまとめたカスタム「レーン」を設定できます。Fastlane でできることはたくさんありますが、このチュートリアルでは主要なアクションをほんの一部だけ使います。

プロジェクトのルートに Fastlane フォルダを作成し、以下のファイルをコピーします: Fastfile

default_platform(:ios)

DEVELOPER_APP_IDENTIFIER = ENV["DEVELOPER_APP_IDENTIFIER"]
DEVELOPER_APP_ID = ENV["DEVELOPER_APP_ID"]
PROVISIONING_PROFILE_SPECIFIER = ENV["PROVISIONING_PROFILE_SPECIFIER"]
TEMP_KEYCHAIN_USER = ENV["TEMP_KEYCHAIN_USER"]
TEMP_KEYCHAIN_PASSWORD = ENV["TEMP_KEYCHAIN_PASSWORD"]
APPLE_ISSUER_ID = ENV["APPLE_ISSUER_ID"]
APPLE_KEY_ID = ENV["APPLE_KEY_ID"]
APPLE_KEY_CONTENT = ENV["APPLE_KEY_CONTENT"]
GIT_USERNAME = ENV["GIT_USERNAME"]
GIT_TOKEN = ENV["GIT_TOKEN"]

def delete_temp_keychain(name)
  delete_keychain(
    name: name
  ) if File.exist? File.expand_path("~/Library/Keychains/#{name}-db")
end

def create_temp_keychain(name, password)
  create_keychain(
    name: name,
    password: password,
    unlock: false,
    timeout: 0
  )
end

def ensure_temp_keychain(name, password)
  delete_temp_keychain(name)
  create_temp_keychain(name, password)
end

platform :ios do
  lane :build do
    build_app(
      configuration: "Release",
      workspace: "./ios/App/App.xcworkspace",
      scheme: "App",
      export_method: "app-store",
      export_options: {
        provisioningProfiles: { 
            DEVELOPER_APP_ID => "#{PROVISIONING_PROFILE_SPECIFIER}"
        }
      }
    )
  end
  lane :refresh_profiles do
    match(
      type: "development",
      force: true)
    match(
      type: "adhoc",
      force: true)
  end
  desc "Register new device"
  lane :register_new_device do  |options|
      device_name = prompt(text: "Enter the device name: ")
      device_udid = prompt(text: "Enter the device UDID: ")
      device_hash = {}
      device_hash[device_name] = device_udid
      register_devices(
                       devices: device_hash
                       )
    refresh_profiles
  end
  lane :closed_beta do
    keychain_name = TEMP_KEYCHAIN_USER
    keychain_password = TEMP_KEYCHAIN_PASSWORD
    ensure_temp_keychain(keychain_name, keychain_password)

    api_key = app_store_connect_api_key(
      key_id: APPLE_KEY_ID,
      issuer_id: APPLE_ISSUER_ID,
      key_content: APPLE_KEY_CONTENT,            
      duration: 1200,            
      in_house: false
    )

    match(
      type: 'appstore',
      git_basic_authorization: Base64.strict_encode64("#{GIT_USERNAME}:#{GIT_TOKEN}"),
      readonly: true,
      keychain_name: keychain_name,
      keychain_password: keychain_password,
      api_key: api_key
    )

    gym(
      configuration: "Release",
      workspace: "./ios/App/App.xcworkspace",
      scheme: "App",
      export_method: "app-store",
      export_options: {
        provisioningProfiles: { 
            DEVELOPER_APP_ID => "#{PROVISIONING_PROFILE_SPECIFIER}"
        }
      }
    )

    pilot(
      apple_id: "#{DEVELOPER_APP_ID}",
      app_identifier: "#{DEVELOPER_APP_IDENTIFIER}",
      skip_waiting_for_build_processing: true,
      skip_submission: true,
      distribute_external: false,
      notify_external_testers: false,
      ipa: "./App.ipa"
    )

    delete_temp_keychain(keychain_name)
  end
  lane :submit_review do
    version = ''
    Dir.chdir("..") do
      file = File.read("package.json")
      data = JSON.parse(file)
      version = data["version"]
    end
    deliver(
      app_version: version,
      submit_for_review: true,
      automatic_release: true,
      force: true, # Skip HTMl report verification
      skip_metadata: false,
      skip_screenshots: false,
      skip_binary_upload: true
    )
  end
end

Appfile

app_identifier(ENV["DEVELOPER_APP_IDENTIFIER"])
apple_id(ENV["FASTLANE_APPLE_ID"])
itc_team_id(ENV["APP_STORE_CONNECT_TEAM_ID"])
team_id(ENV["DEVELOPER_PORTAL_TEAM_ID"])

Fastlane matchを設定

Fastlane match は iOS の code 署名に対する新しいアプローチです。Fastlane match を使えば、チームは iOS アプリに必要な証明書とプロビジョニングプロファイルを簡単に管理できます。

次の名前で新しいプライベートリポジトリを作成します certificates。例えば、GitHub の個人アカウントまたは組織で。

iOS アプリ用に Fastlane match を初期化します。

fastlane match init

次に、オプション #1 (Git Storage) を選択します。

[01:00:00]: fastlane match supports multiple storage modes, please select the one you want to use:1. git2. google_cloud3. s3?

新しく作成したリポジトリの URL を設定します。

[01:00:00]: Please create a new, private git repository to store the certificates and profiles there[01:00:00]: URL of the Git Repo: <YOUR_CERTIFICATES_REPO_URL>

これで Fastlane フォルダ内に、次の名前のファイルがあります。 Matchfile と _git_url_証明書リポジトリの HTTPS URL に設定してください。オプションとして SSH も使用できますが、実行には別の手順が必要です。

# ios/Matchfilegit_url("https://github.com/gitusername/certificates")storage_mode("git")type("appstore")

次に、Fastlane Match で証明書を生成し、求められたら認証情報を入力します。

パスフレーズの入力を求められます。後で GitHub Actions が証明書リポジトリを復号化する際に使用されるため、正しく覚えておいてください。

fastlane match appstore

すべてうまくいけば、次のように表示されます:

[01:40:52]: All required keys, certificates and provisioning profiles are installed 🙌

GitHub と必要な権限に問題が発生した場合は、この 記事 が git の認証トークン生成に役立つかもしれません。

生成された証明書とプロビジョニングプロファイルは、証明書リポジトリのリソースにアップロードされます

App Store Connect 証明書

最後に、あなたの project Xcodeで、アプリのリリース構成のプロビジョニングプロファイルを更新します。

Xcodeの証明書

注意点 💡

一致

CI/CD が証明書とプロビジョニングプロファイルをインポートするには、証明書リポジトリにアクセスできる必要があります。これは、プライベートリポジトリへのアクセスまたは読み取りのスコープを持つパーソナルアクセストークンを生成することで実現できます(事前に使用しておく必要があります)。

GitHub で、以下に移動します 設定 → 開発者設定 → パーソナルアクセストークン → クリック Generate New Token → チェックを入れる repo scope → その後クリック Generate token.

Personal access tokenを作成する

生成されたpersonal access tokenをコピーしておきます。後ほど環境変数として使用します。 GIT_TOKEN.

次に、Fastlaneフォルダに生成されたmatchファイルを Matchfileに置き換えます。

CERTIFICATE_STORE_URL = ENV["CERTIFICATE_STORE_URL"]
GIT_USERNAME = ENV["GIT_USERNAME"]
GIT_TOKEN = ENV["GIT_TOKEN"]
FASTLANE_APPLE_ID = ENV["FASTLANE_APPLE_ID"]

git_url(CERTIFICATE_STORE_URL)
storage_mode("git")
type("appstore")
git_basic_authorization(Base64.strict_encode64("#{GIT_USERNAME}:#{GIT_TOKEN}"))
username(FASTLANE_APPLE_ID)

GitHub Actionsが証明書とプロビジョニングプロファイルをインポートするために使用します。 また、変数はファイルにハードコードする代わりに、GitHub Secretsに設定されます。

ビルド処理中

GitHub Actionsでは、 CI/CD ワークフローの実行に CI/CDワークフローの実行に使用したものです。経験上、App Store Connectでビルドが処理されるまでには10〜15分ほどかかります。

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

私と同様に、プライベートプロジェクトの価格設定を気にしている場合は、 skip_waiting_for_build_processing まで true.

注意点があります。ビルド完了後、ユーザーに配布するためには App Store Connect でアプリのコンプライアンスを手動で更新する必要があります。

これは、プライベートプロジェクトでビルド時間を節約したい場合に更新する、オプションのパラメータです。無料プロジェクトであれば、全く問題ありません。詳細は 料金プランを見る.

3. GitHub Actions のセットアップ

GitHub のシークレットを設定

〜の値がどこから来ているのか、疑問に思ったことはありませんか? ENV 実はもう秘密ではありません。プロジェクトの secret から取得しています。🤦

GitHub secrets の設定

1. APP_STORE_CONNECT_TEAM_ID - 複数のチームに所属している場合は、App Store Connect チームの ID を指定してください。

2. DEVELOPER_APP_ID - App Store Connect で、アプリを選択 → アプリ情報 → 下にスクロールして General Information アプリのセクションで以下を確認してください: Apple ID.

3. DEVELOPER_APP_IDENTIFIER - アプリのBundle Identifier

4. DEVELOPER_PORTAL_TEAM_ID - 複数のチームに所属している場合は、Developer PortalのチームID。

5. FASTLANE_APPLE_ID - アプリの管理に使っているApple IDまたは開発者メールアドレス。

6. GIT_USERNAME &amp; GIT_TOKEN - Gitのユーザー名とパーソナルアクセストークン。

7. MATCH_PASSWORD - matchの初期化時に設定したパスフレーズ(証明書とプロビジョニングプロファイルの復号に使用されます)。

8. PROVISIONING_PROFILE_SPECIFIER - match AppStore <YOUR_APP_BUNDLE_IDENTIFIER>、例: match AppStore com.domain.blabla.demo.

9. TEMP_KEYCHAIN_USER &amp; TEMP_KEYCHAIN_PASSWORD - ワークフロー用の一時キーチェーンユーザー名とパスワードを割り当てます。

10. APPLE_KEY_ID — App Store Connect API Key の 🔺Key ID

11. APPLE_ISSUER_ID — App Store Connect API Key の 🔺Issuer ID

12. APPLE_KEY_CONTENT — App Store Connect API Key 🔺 KeyファイルまたはKeyの内容 .p8, 確認してください

13. CERTIFICATE_STORE_URL — Match keysのリポジトリURL (例: https://github.com/***/fastlane_match.git)

4. GitHubワークフローファイルを設定

GitHub workflowディレクトリを作成します。

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: 2.7.2
      - uses: maierj/fastlane-action@v2.3.0
        env:
          DEVELOPER_APP_IDENTIFIER: ${{ secrets.DEVELOPER_APP_IDENTIFIER }}
          DEVELOPER_APP_ID: ${{ secrets.DEVELOPER_APP_ID }}
          PROVISIONING_PROFILE_SPECIFIER: match AppStore ${{ secrets.DEVELOPER_APP_IDENTIFIER }}
          TEMP_KEYCHAIN_USER: ${{ secrets.TEMP_KEYCHAIN_USER }}
          TEMP_KEYCHAIN_PASSWORD: ${{ secrets.TEMP_KEYCHAIN_PASSWORD }}
          APPLE_ISSUER_ID: ${{ secrets.APPLE_ISSUER_ID }}
          APPLE_KEY_ID: ${{ secrets.APPLE_KEY_ID }}
          APPLE_KEY_CONTENT: ${{ secrets.APPLE_KEY_CONTENT }}
          CERTIFICATE_STORE_URL: https://github.com/${{ secrets.CERTIFICATE_STORE_REPO }}.git
          GIT_USERNAME: ${{ secrets.GIT_USERNAME }}
          GIT_TOKEN: ${{ secrets.PERSONAL_ACCESS_TOKEN }}
          FASTLANE_APPLE_ID: ${{ secrets.FASTLANE_APPLE_ID }}
          MATCH_USERNAME: ${{ secrets.FASTLANE_APPLE_ID }}
          MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }}
          APP_STORE_CONNECT_TEAM_ID: ${{ secrets.APP_STORE_CONNECT_TEAM_ID }}
          DEVELOPER_PORTAL_TEAM_ID: ${{ secrets.DEVELOPER_PORTAL_TEAM_ID }}
        with:
          lane: closed_beta
      - name: Upload release bundle
        uses: actions/upload-artifact@v2
        with:
          name: ios-release
          path: ./App.ipa
          retention-days: 60

このworkflowは、各GitHubの後にトリガーされるように設定します。 タグを設定します、タグの自動化が必要な場合は、こちらを参照してください GitHub アクションによる自動ビルドとリリース してください。

その後、このワークフローが NodeJS の依存関係を取得してインストールし、JavaScript アプリをビルドします。

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

アプリは Ionic を使用する必要はありません。Capacitor ベースであることだけが必須です。古い Cordova モジュールがあっても構いませんが、Capacitor JS プラグインを優先してください。

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

コミットを作成

コミットを 作成すると、リポジトリでアクティブなワークフローが表示されます。

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

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

コミットから開始

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

TestFlight ダッシュボード

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

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

プライベートリポジトリを使っていて、無料プランの実行時間を使い切ってしまい、新しいリリースにお金を払いたくない、またはアプリを手動で提出したい場合を想像してみてください。

さっそく始めましょう

では、まず最初に作成する必要があります my_project_path/fastlane ファイル名を .env, と同じパスに Fastfile, を作成できるように、 シークレット _GitHub にあるプロパティを以下のように定義します:

ローカルマシンからのデプロイ用 .env ファイル

あとは、次に移動して ターミナル を起動します Fastlane をローカル環境で実行:

fastlane closed_beta

❌ 重要: .env ファイルについて。このデータは公開したくないので、必ず .gitignoreに追加してください。例:❌

fastlane/*.env

リモートマシン上の GitHub Actions で実行される場合と同じように、ローカルマシンでも動作するはずです。🍻

ローカルでの Fastlane 実行

ターミナルでの実行: $ Fastlane closed_beta

ここまで来たなら、おめでとうございます!これで Fastlane と GitHub Actions を使った iOS アプリの完全自動化プロセスが整いました。

新しいコミットをプッシュするたびに、Google Play Console のベータチャネルでリリースがビルドされます。 皆さんのフィードバックでこのブログを改善していきます。質問や提案があれば、メールでお知らせください。 martin@capgo.app

デバイス上でビルド

デバイス上でビルドする必要がある場合は、プロビジョニングに手動で追加する必要があります。 デバイスをMacに接続し、デバイスメニューを開いてください。 iOSデバイスメニューを探す 次に、identifierをコピーします iOSのidentifierを確認 その後、次のコマンドを実行します: fastlane register_new_device デバイス名とidentifierの設定を求められます: iOSのidentifierを設定

問題が発生した場合

開発デバイスでテストできないなどの問題がある場合、通常これで解決します。

あなたを救う魔法のコマンドがあります:

fastlane match nuke development
fastlane match development

次に: Shift(⇧)+Command(⌘)+K を押すか、Product > Clean を選択してプロジェクトをクリーンします(「Clean Build Folder」と表示される場合もあります)

その後、デバイスでアプリを再実行してみてください。

ありがとうございます

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

matchを使ったGitHub actionsによる自動Capacitor IOS buildの続きを読む

使用している場合 match を使用した 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は、真にプロフェッショナルなモバイルアプリを作るために必要な最高のインサイトを提供します。