リンクをコピーしました

前の記事で Mac 上の EAS Local ビルドを試しました。
Local ではキーチェーンと EAS の証明書の食い違いでハマったので、切り分けのためにクラウドビルドも回してみたところ、問題なく通りました。
今回は EAS Cloud をメインの配布経路として使い、手元のターミナルから TestFlight に上げるところまで進めます。
ローカルと比べたら比較的簡単なので、そこまでビルドを必要としないならまずはクラウドがおすすめです。

Mac で Xcode を開かずにビルドできるので、CI 向きの構成です。
手順は template-expo-build-cicd をベースに試した内容です。

サンプルリポジトリ

前の記事と同じテンプレートです。
eas.json やビルド・提出の設定が入っているので、自分のプロジェクトの値に差し替えて使います。

git clone https://github.com/testkun08080/template-expo-build-cicd.git
cd template-expo-build-cicd
npm ci

テンプレートは Node.js 20.x 前提です(eas.jsonbase.node20.18.0)。

clone 後に差し替える項目

テンプレートには筆者用の値が入っているので、ビルド前に次を自分のものに変えてください。

ファイル差し替える項目
app.jsonios.bundleIdentifier / extra.eas.projectId
eas.jsonsubmit.production.iosappleId / ascAppId / appleTeamId

extra.eas.projectIdeas init で自分の Expo プロジェクトに紐づけ直すのが確実です。
テンプレートの projectId のまま eas build すると、別のアカウントのプロジェクトに繋がってしまいます。

EAS Cloud と Local の使い分け

前の記事で触れた比較を、Cloud 視点で整理し直します。

EAS CloudEAS Local
Mac 必須不要必須(Xcode 26.x)
ビルド場所Expo サーバー自分の Mac
主な用途手軽・CI 向きネイティブ周りのデバッグ
ビルドログダッシュボードターミナルに直接出る

テンプレートには Local 用の production-local プロファイルもありますが、Cloud では production を使います。

前の記事で済ませていること

Cloud ビルドに進む前に、次が終わっているとスムーズです。
前の記事で一通りやっているので、ここでは要点だけ。

  • App Store Connect にアプリ登録済み(Bundle ID 確定)
  • app.jsonextra.eas.projectId を自分のプロジェクトに設定済み(eas init
  • eas.jsonsubmit.production.ios に次の3つを設定済み
    • appleId — Apple ID(メールアドレス)
    • ascAppId — App Store Connect の App Information にある Apple ID(数字)
    • appleTeamId — Apple Developer の Team ID
  • eas login 済み
  • eas credentials で iOS / production の Distribution 証明書とプロビジョニングプロファイルが Valid

初めて EAS を触る場合は、先に 前の記事の「App Store Connect と Bundle ID」「署名のセットアップ」を済ませてから戻ってきてください。

eas.json の production プロファイル

テンプレートの eas.json は TestFlight 向けにこうなっています(抜粋)。

{
  "cli": {
    "version": ">= 15.0.0",
    "appVersionSource": "remote"
  },
  "build": {
    "base": {
      "node": "20.18.0"
    },
    "production": {
      "extends": "base",
      "channel": "production",
      "autoIncrement": true,
      "ios": {
        "resourceClass": "m-medium"
      }
    },
    "production-local": {
      "extends": "production"
    }
  },
  "submit": {
    "production": {
      "ios": {
        "appleId": "REPLACE_WITH_APPLE_ID",
        "ascAppId": "REPLACE_WITH_ASC_APP_ID",
        "appleTeamId": "REPLACE_WITH_APPLE_TEAM_ID"
      }
    }
  }
}

ascAppId は App Store Connect の App Information にある Apple ID(数字)です。
前の記事の ss6 と同じ欄です。
appleIdappleTeamIdeas submit の認証に使われるので、3つまとめて入れておきます。

任意: ios.image で Xcode バージョンを固定する

テンプレートには ios.image は入っていません。EAS が SDK に合ったデフォルトイメージを選びます。
僕の環境では Local で Xcode 26.2 を使っていたので、クラウドも揃えたくなったときは production.ios に次を足しました。

"ios": {
  "resourceClass": "m-medium",
  "image": "macos-sequoia-15.6-xcode-26.2"
}

SDK のメジャーアップデート直後は EAS のビルドイメージ一覧 と照らして更新すると安定しやすいです。
必須ではなく、Local と Cloud でビルド結果が食い違うときの切り分け用です。

クラウドビルドを実行する

依存関係を入れたあと、クラウドビルドを開始します。
Local との違いは --local を付けない ことだけです。

npm ci
eas build --platform ios --profile production

projectIdeas credentials が済んでいれば、署名まわりはほぼそのまま流用されます。
初回だけ eas init や対話形式の確認が入ることがあります。

ビルドは Expo のダッシュボードでも進捗を追えます。
ターミナルに表示される URL から開くか、expo.devBuilds タブを見てください。

# キャッシュを疑うとき(Local の切り分けでも使った)
eas build --platform ios --profile production --clear-cache

完了すると IPA が EAS 側に保存され、ダッシュボードからダウンロードもできます。
手元に build.ipa は残りません。提出は次の eas submit で行います。

TestFlight に提出する

Cloud ビルド直後は、直近の成功ビルドを提出するのが手軽です。

eas submit --platform ios --profile production --latest

--latest は直近の成功ビルドを対象にします。
特定のビルド ID を指定することもできます。

eas submit --platform ios --profile production --id <BUILD_ID>

Local ビルドのときは eas submit --path ./build.ipa でしたが、Cloud では EAS に上がったビルド成果物を指定する 形になります。
eas.jsonsubmit.production.iosappleId / ascAppId / appleTeamId)が入っていれば提出先は自動で解決されます。

初回の eas submit では、App Store Connect API キーの登録を案内されることがあります。
画面の指示に従えば、fastlane のように match 用 Git リポジトリを用意する必要はありません。

テンプレートの app.json には ITSAppUsesNonExemptEncryption: false が入っているので、暗号化の対話は出ないことが多いです。
別プロジェクトで質問が出たら、HTTPS だけ使っている一般的なアプリなら Y で進めます(前の記事の ss13 参照)。

non-interactive フラグについて

CI やスクリプトに載せるときは --non-interactive を付けます。
projectId、署名、submit 設定の初回セットアップが終わってから使うのが安全です。

eas build --platform ios --profile production --non-interactive
eas submit --platform ios --profile production --latest --non-interactive

手元のターミナルから使う分には eas login で足ります。EXPO_TOKEN が必要になるのは GitHub Actions から自動化するときだけです。

Xcode Cloud での配布例は 次の記事で紹介します。

よくあるトラブル

ビルド番号の重複

appVersionSource: remoteautoIncrement を有効にしていれば、EAS 側でビルド番号が管理されるので重複しにくいです。
app.jsonios.buildNumber を手動固定していると衝突することがあるので、production では remote 管理に寄せるのが楽でした。

Xcode バージョンの不一致

テンプレート標準では ios.image は未指定です。
Local と Cloud で結果が食い違うときは、前のセクションのとおり ios.image を足して揃えてみてください。

Local は落ちるが Cloud は通る

前の記事で遭遇したパターンです。
Cloud が通るなら EAS の credentials は正しいので、Local 側は Mac のキーチェーンと Distribution 証明書の不一致を疑うのが近道です。

まとめ

とにかく簡単。

  • eas build--local なし)で Expo のサーバー上に IPA を生成できる
  • 提出は eas submit --latest で Cloud ビルド成果物をそのまま TestFlight に送れる
  • 前の記事で整えた署名設定をそのまま使える
  • Mac で Xcode を開かずに回せるので、CI 向きの配布経路になる

次の記事では、EAS を使わず Xcode Cloud で TestFlight まで持っていく方法を紹介します。
Apple Developer Program に含まれる無料枠が個人開発向きです。

Expo × Xcode Cloud で TestFlight に上げる

関連リンク