iOS Local Build & Submission ローカルビルド → App Store Connect アップロード → TestFlight / 審査提出の完全ワークフロー。 基本方針 ローカルビルドをデフォルトにする (EAS Buildは使わない) EAS Free tier は月30ビルド。デバッグ反復で一瞬で溶ける EASはgit cloneベース → gitに入っていないファイルはビルドに含まれない → 事故の元 ローカルビルドはファイルシステムを直接使う → 安全・高速・無制限 Phase 0: ビルド前チェック 0.1 アプリ特定
どのアプリをビルドするか確認
ls -d */app.json
→ muednote-mobile/app.json, muedear/app.json
0.2 ブランチ確認 目的 ブランチ App Store 審査提出 main TestFlight テスト feature ブランチ OK git branch --show-current git status 0.3 バージョン・ビルド番号の確認
app.json から現在の version と buildNumber を確認
- cat
- <
- APP_DIR
- >
- /app.json
- |
- grep
- -E
- '"version"|"buildNumber"'
- ルール:
- version
-
- App Store に表示されるバージョン(例: 0.8.4)
- buildNumber
- 同一 version 内で一意。 常に既存の最大値 + 1 にする App Store Connect で使用済みの buildNumber は再利用不可 version train が閉じたら(リジェクト等)、version を上げる必要あり 0.4 .env 管理 重要: .env の値は prebuild 時ではなく、xcodebuild archive 時に Metro bundler が注入する。
現在の .env を確認
cat < APP_DIR
/.env
バックアップ(初回のみ)
cp < APP_DIR
/.env < APP_DIR
/.env.backup 用途 CLERK_KEY API_URL 本番 (App Store) pk_live_... https://mued.jp テスト (TestFlight) pk_test_... preview deploy URL TestFlight ビルドの場合:
.env を TestFlight 用に変更
EXPO_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_test_...
EXPO_PUBLIC_API_URL=https://.vercel.app
本番ビルドの場合:
.env が本番値であることを確認
EXPO_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_live_...
EXPO_PUBLIC_API_URL=https://mued.jp
ビルド後は必ず本番値に戻す: cp < APP_DIR
/.env.backup < APP_DIR
/.env Phase 1: ローカルビルド 1.1 依存関係インストール & Prebuild cd < APP_DIR
npm install npx expo prebuild --clean --clean は ios/ を削除して再生成する。常につける。 1.2 Archive xcodebuild -workspace ios/ < SCHEME
.xcworkspace \ -scheme < SCHEME
\ -configuration Release \ -archivePath build/ < SCHEME
.xcarchive \ -destination "generic/platform=iOS" \ DEVELOPMENT_TEAM = F529L4WT3V \ CODE_SIGN_STYLE = Automatic \ -allowProvisioningUpdates \ archive アプリ別の値: アプリ SCHEME workspace MUEDnote MUEDnote ios/MUEDnote.xcworkspace MUEDear MUEDear ios/MUEDear.xcworkspace 1.3 Export & Upload xcodebuild -exportArchive \ -archivePath build/ < SCHEME
.xcarchive \ -exportPath build \ -exportOptionsPlist ExportOptions.plist \ -allowProvisioningUpdates -allowProvisioningUpdates がないと "No profiles found" エラーになる。 1.4 ExportOptions.plist 各アプリディレクトリに配置済み。なければ作成:
- <!
- DOCTYPE
- plist
- PUBLIC
- "-//Apple//DTD PLIST 1.0//EN"
- "http://www.apple.com/DTDs/PropertyList-1.0.dtd"
- >
- <
- plist
- version
- =
- "
- 1.0
- "
- >
- <
- dict
- >
- <
- key
- >
- method
- </
- key
- >
- <
- string
- >
- app-store-connect
- </
- string
- >
- <
- key
- >
- signingStyle
- </
- key
- >
- <
- string
- >
- automatic
- </
- string
- >
- <
- key
- >
- teamID
- </
- key
- >
- <
- string
- >
- F529L4WT3V
- </
- string
- >
- <
- key
- >
- uploadSymbols
- </
- key
- >
- <
- true
- />
- <
- key
- >
- destination
- </
- key
- >
- <
- string
- >
- upload
- </
- string
- >
- </
- dict
- >
- </
- plist
- >
- 1.5 ビルド後の .env 復元
- cp
- <
- APP_DIR
- >
- /.env.backup
- <
- APP_DIR
- >
- /.env
- Phase 2: App Store Connect 操作
- アップロード完了後、5〜15分で処理完了。
- 2.1 Chrome 拡張を使う場合
- Claude in Chrome 拡張で App Store Connect を操作できる。
- 1. tabs_context_mcp で接続確認
- 2. appstoreconnect.apple.com に navigate
- 3. ユーザーにログインしてもらう(パスワード入力は禁止)
- 4. ログイン後、アプリ一覧からスクリーンショットで状態確認
- 注意:
- Chrome 拡張の接続は不安定。切れたら
- tabs_context_mcp
- で再接続
- Apple ID / パスワードは絶対に入力しない。ユーザーに任せる
- 「審査へ提出」等の不可逆操作は実行前にユーザー確認を取る
- 2.2 TestFlight 配信(テスト用)
- App Store Connect → アプリ →
- TestFlight
- タブ
- ビルドが「終了」(処理完了)であることを確認
- Internal Testers
- グループを確認
- 自動追加されていれば即テスト可能
- されていなければ「ビルド」タブからビルドを追加
- 輸出コンプライアンス:
- ITSAppUsesNonExemptEncryption: false
- が app.json に設定済みなら自動回答
- 未設定の場合、手動で「いいえ」を選択
- 2.3 App Store 審査提出
- ⚠ ビルド前にデバッグ残骸を除去:
- Settings画面の Diagnose ボタン → 削除
- apiClient.ts
- 等のデバッグ
- console.log
- → 削除
- 一時的なデバッグUI(ステータスバナー等) → 削除
- .env
- が本番値であること → 確認
- App Store Connect → アプリ →
- 配信
- タブ
- 新バージョンを作成(+ボタン → バージョン番号入力)
- 必須項目を確認:
- スクリーンショット
-
- 前バージョンから引き継がれるが、保存が必要な場合あり
- ビルド
-
- 「ビルドを追加」から該当ビルドを選択
- このバージョンの最新情報
- 更新内容を英語で記載
保存
→
審査用に追加
→
審査へ提出
よくあるエラー:
エラー
対処
「ビルドを選択してください」
ビルドが保存されていない。再度追加→保存
「このバージョンの最新情報は必須」
What's New を記入
「スクリーンショットが必要」
新バージョンは初回保存後にスクショが引き継がれる
「バージョンXのトレインはクローズ」
version を上げる(0.8.3 → 0.8.4)
Phase 3: TestFlight 検証(UIデバッグ)
TestFlight では
console.log
は見えない。
問題の切り分けにはUI上のデバッグ表示が必須。
3.0 TestFlight 向けデバッグ診断の実装
TestFlight ビルドで新機能やAPI連携をテストする場合、Settings画面に
Diagnose ボタン
を必ず設置する:
// Settings画面に追加
const
handleDiagnose
=
async
(
)
=>
{
const
lines
:
string
[
]
=
[
]
;
// 1. 認証状態
lines
.
push
(
Clerk isSignedIn: ${ clerkIsSignedIn }) ; lines . push (Clerk userId: ${ clerkUserId ?? 'null' }) ; // 2. トークン取得テスト try { const token = await getToken ( ) ; lines . push (Token: ${ token ?OK (len= ${ token . length } ): 'NULL' }) ; } catch ( err : any ) { lines . push (Token ERROR: ${ err . message }) ; } // 3. API疎通テスト(直接 fetch で生レスポンスを確認) try { const resp = await fetch (${ BASE_URL } /api/target-endpoint, { headers } ) ; const raw = await resp . json ( ) ; // apiSuccess ラップの有無を確認 lines . push (API: ${ resp . status }) ; lines . push (Has data wrapper: ${ 'data' in raw }) ; lines . push (Response keys: ${ Object . keys ( raw ) . join ( ', ' ) }) ; } catch ( err : any ) { lines . push (API ERROR: ${ err . message }) ; } Alert . alert ( 'Diagnose' , lines . join ( '\n' ) ) ; } ; 確認ポイント: トークンが NULL → Clerk セッションの問題 トークン OK だが API が 401 → サーバー側のJWT検証の問題 API 200 だがデータが undefined → レスポンスラッパー( apiSuccess )の unwrap 漏れ Has data wrapper: true → apiClient.handleResponse でアンラップが必要 リリース(審査提出)前に必ず: Diagnose ボタンを削除(またはタップ回数イースターエッグ化) apiClient.ts 等の console.log('[API] Token obtained...') 等のデバッグログを削除 デバッグ用の一時UIコンポーネント(バナー、ステータス表示等)を削除 これらを確認してからビルド → 審査提出する。 デバッグUIが残ったまま審査提出しない Phase 4: ビルド前検証 4.1 Provider で null を返さない grep -r "return null" < APP_DIR/src/providers/ 2
/dev/null NG: if (!isLoaded) return null; OK: ローディング UI を返す 4.2 ATT プラグイン設定(広告使用アプリのみ) grep -A5 "expo-tracking-transparency" < APP_DIR
/app.json ベア文字列 "expo-tracking-transparency" はNG。オブジェクト形式が必須。 4.3 gitignore の確認
modules/*/ios/ が除外されていないか確認
ios/ ではなく /ios/ (ルート限定) であること
- grep
- "^ios/"
- <
- APP_DIR
- >
- /.gitignore
- grep
- "^/ios/"
- <
- APP_DIR
- >
- /.gitignore
- ios/
- → 全階層の ios/ を除外(ネイティブモジュールのSwiftソースも消える)
- /ios/
- → ルートの ios/ のみ除外(正しい)
- アプリ別クイックリファレンス
- MUEDnote
- cd
- muednote-mobile
- npm
- install
- &&
- npx expo prebuild
- --clean
- xcodebuild
- -workspace
- ios/MUEDnote.xcworkspace
- -scheme
- MUEDnote
- \
- -configuration
- Release
- -archivePath
- build/MUEDnote.xcarchive
- \
- -destination
- "generic/platform=iOS"
- DEVELOPMENT_TEAM
- =
- F529L4WT3V
- \
- CODE_SIGN_STYLE
- =
- Automatic
- -allowProvisioningUpdates
- archive
- xcodebuild
- -exportArchive
- -archivePath
- build/MUEDnote.xcarchive
- \
- -exportPath
- build
- -exportOptionsPlist
- ExportOptions.plist
- -allowProvisioningUpdates
- Bundle ID:
- com.mued.note
- Apple Sign In: あり
- MUEDear
- cd
- muedear
- npm
- install
- &&
- npx expo prebuild
- --clean
- xcodebuild
- -workspace
- ios/MUEDear.xcworkspace
- -scheme
- MUEDear
- \
- -configuration
- Release
- -archivePath
- build/MUEDear.xcarchive
- \
- -destination
- "generic/platform=iOS"
- DEVELOPMENT_TEAM
- =
- F529L4WT3V
- \
- CODE_SIGN_STYLE
- =
- Automatic
- -allowProvisioningUpdates
- archive
- xcodebuild
- -exportArchive
- -archivePath
- build/MUEDear.xcarchive
- \
- -exportPath
- build
- -exportOptionsPlist
- ExportOptions.plist
- -allowProvisioningUpdates
- Bundle ID:
- com.mued.muedear
- AdMob + ATT: あり
- Gotchas
- EAS Build は git clone ベース
-
- ローカルにあっても git に入っていないファイルはビルドに含まれない。
- .gitignore
- の
- ios/
- が
- modules/*/ios/
- の Swift ソースまで除外していた事故例あり
- version train がクローズ
-
- App Store Connect でバージョンがリジェクト等でクローズされたら、同じバージョンでは再提出不可。version を上げる
- buildNumber は使い捨て
-
- 一度使った buildNumber は再利用不可。App Store Connect のビルド一覧で最新番号を確認してからインクリメント
- .env はビルド後に必ず戻す
-
- TestFlight用の
- pk_test
- のまま本番ビルドすると事故る
- prebuild の --clean は常につける
-
- 古いネイティブコードが残って混乱する原因になる
- 新バージョンのスクショは一度保存が必要
- 新バージョン作成直後はスクショが空に見えるが、保存すると前バージョンから引き継がれる Common Rejection Reasons & Fixes 1. App Completeness(黒い画面) Provider が null を返している。ローディング UI を返すように修正。 2. ATT Not Shown expo-tracking-transparency のプラグイン設定がベア文字列。オブジェクト形式に変更。 3. Accurate Metadata スクリーンショットが実際のアプリと一致しない。最新版に更新。 4. Sign In Issues デモアカウント情報がアプリのフォームと一致しない。プレースホルダーが「メールアドレス」ならメール形式で記載。 Resolution Center コメントテンプレート We have addressed the issue identified in the previous review: [Issue] (fixed) - Root cause: [Technical explanation] - Fix: [What was changed] - File changed: [File path] Build [N] contains this fix. Thank you for your review.