Expo で作っている 自作中のアプリ を iOS で配布するにあたり、まずは EAS Local で Mac 上に IPA を作り、TestFlight に上げるところまで試しました。
eas build --local を使えば、Expo のクラウドに任せずローカルのXcodeでビルドできます。
記録用に template-expo-build-cicd というテンプレートリポジトリも作ったので、つまづいたところを共有しながらメモとして残します。
EAS と App Store Connect の連携や証明書まわりは、すでに別プロジェクトで触っていたので今回はスムーズに進みました。
初めての場合は EAS Build の公式ドキュメント を一度読んでおくと安心です。
サンプルリポジトリ
この記事の手順はテンプレートとして作った template-expo-build-cicd をベースに試しました。
eas.json やビルド・提出の設定が入っているので、Bundle ID などを自分のものに差し替えて使えます。
git clone https://github.com/testkun08080/template-expo-build-cicd.git
cd template-expo-build-cicd
npm ciclone 後に差し替える項目
テンプレートには筆者用の値が入っているので、ビルド前に次を自分のものに変えてください。
| ファイル | 差し替える項目 |
|---|---|
app.json | ios.bundleIdentifier / extra.eas.projectId |
eas.json | submit.production.ios の appleId / ascAppId / appleTeamId |
extra.eas.projectId は eas init で自分の Expo プロジェクトに紐づけ直すのが確実です。
テンプレートの projectId のまま eas build すると、別のアカウントのプロジェクトに繋がってしまいます。
テンプレートの app.json(抜粋)
{
"expo": {
"name": "template-expo-build",
"slug": "template-expo-build",
"ios": {
"bundleIdentifier": "com.testkun08080.template-expo-build",
"infoPlist": {
"ITSAppUsesNonExemptEncryption": false
}
},
"extra": {
"eas": {
"projectId": "a77f74e1-5302-47a4-a581-eace64b7f025"
}
}
}
}bundleIdentifier は App Store Connect 側の Bundle ID と揃えます。
projectId は自分の EAS プロジェクトの値に差し替えます。
テンプレートの eas.json(抜粋)
Local ビルドでは production-local(中身は production の継承)か、そのまま production を使います。
{
"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"
}
}
}
}appleId— Apple ID(メールアドレス)ascAppId— App Store Connect の App Information にある Apple ID(数字)appleTeamId— Apple Developer の Team ID
この3つを自分の値に書き換えておくと、あとで eas submit が楽です。
EAS Cloud と Local の使い分け
| EAS Cloud | EAS Local | |
|---|---|---|
| Mac 必須 | 不要 | 必須(Xcode 26.x) |
| ビルド場所 | Expo サーバー | 自分の Mac |
| 主な用途 | 手軽・CI 向き | ネイティブ周りのデバッグ |
| ビルドログ | ダッシュボード | ターミナルに直接出る |
普段は Xcode Cloud で回していますが、同じことを EAS Local でも経験しておくと、署名まわりのトラブルが起きたときに切り分けしやすいと感じました。
前提
- Apple Developer Program への登録済み
- App Store Connect にアプリを登録済み(Bundle ID が確定していること)
eas.jsonの production プロファイルが設定済みeas login済み- Xcode 26.2 がインストール済み(Expo SDK 55 向け)
- Node.js 22 系
Xcode のバージョン確認:
xcodebuild -versionApp Store Connect と Bundle ID
TestFlight に上げるには、先に App Store Connect でアプリを作っておく必要があります。
app.json の ios.bundleIdentifier と同じ Bundle ID を選びます。
Bundle ID まわりは次のどちらかで進められます。
- Identifiers の作成ページで先に作る
- ビルドしながら対話で作る
npx eas-cli build --profile production --platform ios --local後者だと、証明書と Bundle ID をその場で作ってしまう流れにもできます。
僕はテンプレを使うときは、先に Bundle ID を決めて app.json に書いておく方が迷いが少なかったです。
その後、新規アプリの作成も行います。

作成後、App Information の Apple ID(数字)を eas.json の submit.production.ios.ascAppId に入れておきます。
テンプレートだとプレースホルダのままなので、例えばこう書き換えます。
{
"submit": {
"production": {
"ios": {
"appleId": "your-apple-id@example.com",
"ascAppId": "1234567890",
"appleTeamId": "ABCD123456"
}
}
}
}ascAppId は下のスクショの数字です。appleId と appleTeamId も一緒に入れておくと、提出時の対話が減ります。

Apple Developer 側でも、同じ Bundle ID が登録されていることを確認します。

EAS プロジェクトの作成
初回の eas build では、EAS プロジェクトがまだ紐づいていないことがあります。
対話形式で「自動作成しますか?」と聞かれたら Y で進めれば、app.json に projectId が付与されます。


署名のセットアップ
Local ビルドでも、初回は eas credentials で Distribution 証明書とプロビジョニングプロファイルを EAS に登録しておくのが楽でした。
fastlane match のように証明書用 Git リポジトリは不要です。
eas credentialsPlatform で iOS → production を選ぶと、Apple Developer へのログインや証明書作成が走ります。


EAS ダッシュボードの Credentials で、証明書とプロビジョニングプロファイルが Valid になっていれば OK です。

対話形式のセットアップが終わると、ターミナルにプロビジョニングプロファイル作成完了のメッセージが出ます。

ローカルビルドを実行する
依存関係を入れてから、ローカルビルドを実行します。
npm ci --legacy-peer-deps
eas build --platform ios --local --profile production \
--output ./build.ipa初回は --non-interactive を外して対話形式で進めると、足りない設定に気づきやすいです(後述)。
僕が遭遇したエラー
.xcworkspace を Xcode で開いて Archive は成功するのに、EAS Local だけ失敗したことがありました。
ログを見ると、プロビジョニングプロファイルに署名証明書が含まれていない、という内容でした。
[RUN_FASTLANE]
❌ Provisioning profile "*[expo] com.testkun08080.template-expo-build AppStore 2026-07-10T07:25:34.991Z" doesn't include signing certificate "Apple Distribution: myname (XXXXXXXX)". (in target 'templateexpobuild' from project 'templateexpobuild')切り分けの手順
まずクラウドビルドで署名まわりが通るか確認しました。
npx eas-cli build --profile production --platform ios --clear-cache僕の環境ではクラウドは問題なく通ったので、Mac のキーチェーンと EAS に登録されている証明書の食い違い が原因だと判断しました。
手元のMacとの証明書の比較にDeveloper ポータルから .cer をダウンロードして比較します。

キーチェーンアクセスで distri などと検索すると、Distribution 証明書が見つかります。
Local ビルドでハマったときは、ここに表示される証明書と EAS 側の証明書が一致しているかを確認しました。

次を順に確認します。
security find-identity -v -p codesigning- キーチェーンアプリで Distribution 証明書を検索する(上の ss10)
- EAS Credentials に表示されている Distribution 証明書と一致するか
- Apple Developer でダウンロードした
.cerのシリアルナンバーが同じか
一つでも違うと、上記の Provisioning profile エラーになります。
古い証明書がキーチェーンに残っているケースも多いので、使わないものは削除するか、EAS 側の証明書に合わせて作り直すのが早いです。
ビルド成功
証明書を揃えたあと、同じコマンドで Local ビルドが通りました。
カレントディレクトリに build.ipa が出力されます。

TestFlight に提出する
eas submit --platform ios --path ./build.ipaeas.json の submit.production.ios.ascAppId が設定されていれば、提出先は自動で解決されます。
初回は暗号化に関する質問が出るので、HTTPS だけ使っている一般的なアプリなら Y で進めます。

non-interactive フラグについて
--non-interactive は CI やスクリプト実行向けです。
署名や EAS プロジェクトの初回セットアップが終わってから付けるのが安全です。
eas build --platform ios --local --profile production \
--output ./build.ipa --non-interactiveよくあるトラブル
プロビジョニングプロファイルと証明書の不一致
今回いちばん時間を取られたのがこれです。
Xcode の Archive が通っても EAS Local が落ちるときは、キーチェーン・EAS・Apple Developer の3か所で Distribution 証明書のシリアルナンバーを突き合わせてみてください。
ディスク容量
Local ビルドは DerivedData や Pods を Mac 上に展開するため、数 GB の空き容量があると安心です。
まとめ
eas build --localで Mac 上に IPA を生成できる- 提出は
eas submit --path ./build.ipaで Cloud ビルドと同じ - 署名トラブルはキーチェーンと EAS Credentials の突き合わせが近道
- ネイティブ周りのデバッグに向くが、Xcode 26.x とディスク容量が必要
次の記事では、EAS Cloud でクラウドビルドする方法を紹介します。
Localでやるのと比べたら二つぐらいのコマンドで終わるので簡単です。。。
→ Expo × EAS Cloud でローカルから TestFlight に上げる