アップロードのプログレスバーは100%まで進み、「正常に送信されました」と表示されました——それなのに、App Store Connect の TestFlight タブを開いてもビルドが出てきません。ステータスは「処理中(Processing)」のまま、30分待っても、1時間待っても変わりませんでした。これは私自身、複数のアプリを並行して運用するなかで、何度か手が止まった場面です。
厄介なのは、エラーが画面に出ないことです。アップロードは成功しているので、どこを直せばいいのかの手がかりがありません。ただ静かに「処理中」が続くだけで、審査に提出するボタンも押せません。
ここでは、Rork(React Native / Expo 版)や Rork Max(Swift ネイティブ版)で書き出したアプリが App Store Connect の処理中で止まったとき、私が実際にたどった切り分けの順番と、それぞれの直し方を整理します。想像で書いた一般論ではなく、自分が詰まって解決したルートだけをまとめています。
「処理中」には2種類あることを最初に区別する
まず押さえておきたいのは、「処理中」と一口に言っても、内部では性質の違う2つの状態が混ざっている点です。
ひとつは、Apple のサーバーが受け取ったバイナリを展開・検証している正常な処理です。これは多くの場合5〜15分、混雑時でも30分ほどで終わります。新しい Xcode / SDK のリリース直後は世界中のアップロードが集中するため、純粋に行列が長くなることがあります。
もうひとつは、検証の途中で問題が見つかり、Apple がそれを「却下」ではなく「無言の停止」として扱っているケースです。この場合、ステータスはいつまでも処理中のまま、あるいは数時間後にビルドそのものが消えます。Rork で書き出したアプリで私がハマったのは、ほぼ後者でした。
切り分けの第一歩は、30分待っても変わらないなら正常な行列ではないと見切ることです。待ち続けても解決しないので、原因の特定に移ります。
まず登録メールと「アクティビティ」を確認する
App Store Connect の画面には出なくても、Apple は問題を見つけるとビルド責任者のメールアドレスに通知を送ってきます。私の場合、TestFlight 画面には何も出ていないのに、受信トレイに「App Store Connect」からのメールで具体的な拒否理由が届いていた、ということが何度かありました。
確認する順番はこうしています。
まず Apple Developer アカウントに登録しているメールの受信トレイと迷惑メールフォルダを見ます。次に App Store Connect の対象アプリ → 「TestFlight」→ 該当ビルドの「アクティビティ」や、左メニューの通知ベルを確認します。メールが届いていれば、そこに ITMS から始まるエラーコードか、Invalid Binary(無効なバイナリ)の理由が書かれています。
メールの文面は長いのですが、読むべきところは ITMS の番号だけです。私が Rork で書き出したアプリで実際に受け取った番号と、この記事のどの節に対応するかを先に並べておきます。
| コード | 件名に出る言葉 | 意味 | 対応する節 |
|---|---|---|---|
| ITMS-90717 | Invalid App Store Icon | 1024×1024 アイコンに透過(アルファ)が残っている | 原因2 |
| ITMS-90189 | Redundant Binary Upload | 同じバージョン×ビルド番号を二度上げた | 原因3 |
| ITMS-90725 | SDK version issue | 必須 SDK より古い Xcode でビルドしている | 原因4 |
| ITMS-90683 | Missing Purpose String | カメラや写真などの用途説明文が Info.plist に無い | 原因4(別記事へ) |
ここで原因が判明すれば、以降の切り分けは不要です。メールが何も来ていない場合だけ、次に進みます。
原因1: 暗号化輸出コンプライアンスの未設定
Rork で書き出したアプリで最も多く遭遇したのが、これです。アプリは HTTPS 通信を行うだけでも「暗号化を使用している」とみなされ、輸出コンプライアンスの申告が求められます。これが未設定だと、ビルドは処理中で止まりやすくなります。
恒久的に解決するには、app.json(Expo)または Info.plist(Swift)に申告を埋め込んでおきます。標準的な暗号化(HTTPS のみ)しか使っていないアプリなら、次の1行で「審査のたびに聞かれる」状態から解放されます。
Expo(app.json)の場合:
{
"expo": {
"ios": {
"config": {
"usesNonExemptEncryption": false
}
}
}
}Swift(Info.plist)の場合は、キーを直接追加します。
<key>ITSAppUsesNonExemptEncryption</key>
<false/>false を指定できるのは、自前で独自の暗号化を実装しておらず、OS 標準の HTTPS や標準暗号 API しか使っていない場合です。独自暗号を組み込んでいるアプリは安易に false にせず、Apple の輸出コンプライアンス要件を確認してください。この1行を入れておくと、次回以降のアップロードで処理が止まりにくくなり、毎回の手動申告も不要になります。
原因2: アイコンの欠落・透過・サイズ不正
処理中で止まり、数時間後にビルドが消える——このパターンで私が突き止めた原因のひとつが、アイコンでした。App Store 用の 1024×1024 アイコンにアルファチャンネル(透過)が含まれていると、検証段階で弾かれます。画面にはエラーが出ず、ただビルドが現れません。
確認はコマンドで一発でできます。透過の有無を見るには、手元のアイコン画像に対して次を実行します。
# アイコンにアルファチャンネルが含まれていないか確認する
sips -g hasAlpha AppIcon-1024.png
# 出力に "hasAlpha: yes" が出たら透過が残っている透過が残っていた場合は、白などの不透明な背景に合成して書き出し直します。
# 透過を白背景で埋めて不透明なPNGに変換する(ImageMagick)
magick AppIcon-1024.png -background white -alpha remove -alpha off AppIcon-1024-fixed.pngExpo で managed workflow を使っている場合は、app.json の ios.icon に指定する画像そのものを不透明にしておけば、ビルド時に正しいアイコンセットが生成されます。Rork が自動生成したプレースホルダーアイコンをそのまま使うと透過が残っていることがあるので、公開前に必ず差し替えるようにしています。
壁紙アプリのアイコンを差し替えたとき、書き出し設定を「背景を透明に」のまま保存していたことに気づいたのは、ビルドが二度消えたあとでした。見た目は同じでも、ファイルの中身は違っていたのです。
原因3: ビルド番号の重複
同じ バージョン × ビルド番号 の組み合わせは、App Store Connect に二度アップロードできません。ところが、アップロード自体は成功してしまい、処理中で止まったように見えることがあります。実際には「既存ビルドと衝突したので破棄された」状態です。
私はこれを避けるため、ビルド番号を必ず単調増加させています。Expo の EAS Build なら、リモートで自動採番する設定が確実です。
{
"cli": {
"appVersionSource": "remote"
},
"build": {
"production": {
"autoIncrement": true
}
}
}手動で番号を管理している場合は、アップロード前に App Store Connect 上の最新ビルド番号を確認し、必ずそれより大きい値にします。バージョン を上げたときはビルド番号を1にリセットしても構いませんが、同一バージョン内では重複させないことが鉄則です。
原因4: SDK の古さ・dSYM 不足・無効なバイナリで「無言の却下」
処理が長引いた末にビルドが消える最後のパターンが、バイナリ自体の検証失敗です。クラッシュ収集のための dSYM が欠落している、対応していないアーキテクチャが混ざっている、といった理由で Apple が無効と判断します。多くはメール通知が来ますが、来ないこともあります。
2026年に入ってから増えたのが、SDK の古さです。Apple の告知では、2026年4月28日以降、App Store Connect へアップロードするアプリは Xcode 26(iOS 26 SDK)以降でビルドされている必要があります。手元の Mac の Xcode を上げ忘れたまま書き出すと、ITMS-90725(SDK version issue)が返ってくるか、通知すら来ずにビルドが消えます。EAS Build を使っている場合は eas.json の image が古い Xcode を指したままになっていないかを、年に一度は見直すようにしています。ベータ版の SDK でビルドしたときの挙動は、ベータ SDK でビルドしたアプリは、TestFlight には配れても審査には出せませんに分けて書き残しています。
ここで有効なのが、アップロードする前にローカルで検証してしまうことです。.ipa を作った段階で altool にかければ、App Store Connect の処理を待たずに同等の検証結果が得られます。
# アップロード前にローカルでバイナリを検証する
xcrun altool --validate-app \
-f build/MyApp.ipa \
-t ios \
--apiKey "YOUR_KEY_ID" \
--apiIssuer "YOUR_ISSUER_ID"ここでエラーが返れば、処理中で何時間も待つ前に原因がわかります。私は公開フローにこの検証を1ステップ挟むようにしてから、「アップロードしたのに消える」事故がほぼなくなりました。Rork Max の2クリック公開のように書き出しから提出までが自動化されている場合でも、生成された .ipa を一度手元で検証する余地は残しておくと安心です。
画面を見張る代わりに、API で処理状態を取りにいく
ブラウザのタブをリロードし続ける時間が、いちばん心をすり減らします。私がいまやっているのは、App Store Connect API から最新ビルドの processingState を取ってくることです。値は PROCESSING / VALID / FAILED / INVALID の4つで、画面には出ない FAILED と INVALID が API では区別されて返ってきます。
API キーは App Store Connect の「ユーザとアクセス」→「統合」で発行し、.p8 ファイルと Key ID・Issuer ID を控えておきます。ローカルの Python で動かす最小構成はこれだけです。
# asc_build_state.py — 最新ビルドの processingState を App Store Connect API で取得する
# 事前準備: pip install pyjwt cryptography requests
import sys
import time
import jwt
import requests
KEY_ID = "YOUR_KEY_ID"
ISSUER_ID = "YOUR_ISSUER_ID"
PRIVATE_KEY_PATH = "AuthKey_YOUR_KEY_ID.p8"
APP_ID = "YOUR_APP_ID" # App Store Connect の「Apple ID」欄にある数字
def make_token() -> str:
"""有効期限 10 分の ES256 JWT を作る(上限は 20 分)"""
now = int(time.time())
payload = {
"iss": ISSUER_ID,
"iat": now,
"exp": now + 600,
"aud": "appstoreconnect-v1",
}
with open(PRIVATE_KEY_PATH) as f:
return jwt.encode(payload, f.read(), algorithm="ES256", headers={"kid": KEY_ID})
def latest_build() -> dict | None:
"""アップロード日時が最新のビルドを 1 件だけ取る"""
res = requests.get(
"https://api.appstoreconnect.apple.com/v1/builds",
headers={"Authorization": f"Bearer {make_token()}"},
params={"filter[app]": APP_ID, "sort": "-uploadedDate", "limit": 1},
timeout=30,
)
res.raise_for_status()
data = res.json()["data"]
return data[0]["attributes"] if data else None
if __name__ == "__main__":
build = latest_build()
if build is None:
print("ビルドがまだ API に現れていません(アップロード直後は数分かかります)")
sys.exit(2)
print(build["version"], build["processingState"], build["uploadedDate"])
# VALID なら 0、それ以外は 1 を返して、シェルの while ループで待てるようにする
sys.exit(0 if build["processingState"] == "VALID" else 1)このスクリプトを1分おきに回すだけで、Apple の処理が終わった瞬間にターミナルが教えてくれます。
# VALID になるまで 60 秒おきに確認する(Ctrl+C で止める)
until python3 asc_build_state.py; do sleep 60; doneここで読み取れることが3つあります。FAILED か INVALID が返ってきたら、メールが来ていなくても検証で落ちたと確定します。20分以上 PROCESSING のままなら、原因1〜4を順に疑います。そして、アップロードが成功したはずなのに API の一覧から消えていたら、それは重複ビルドとして破棄された合図です——ビルド番号を上げて出し直す以外に道はありません。
待つのは画面ではなく、値です。 この線引きをしてから、処理中の1時間を別の作業に充てられるようになりました。
それでも処理中が続くとき
ここまでの原因が当てはまらず、メールも来ず、それでも1時間以上処理中が続く場合は、Apple 側の純粋な遅延を疑います。新しい iOS / Xcode のリリース直後は、世界中のビルドが集中して数時間かかることが現実にあります。
このときの私の対処はシンプルです。まず Apple の System Status ページで「App Store Connect」と「TestFlight」が正常稼働かを確認します。問題が出ていれば、待つしかありません。正常稼働なのに3時間以上動かない場合は、まったく同じビルドを再アップロードしないようにしています(重複で弾かれます)。ビルド番号だけを1つ上げて、クリーンに作り直したものを上げ直します。これで多くは抜けます。
次にやること
もし今まさに処理中で止まっているなら、まず登録メールを確認し、暗号化輸出コンプライアンスの申告(usesNonExemptEncryption: false)が入っているかを app.json か Info.plist で確かめてみてください。私の経験では、Rork で書き出したアプリの「処理中スタック」の半分以上は、この1行で解決します。
そのうえで時間があれば、上の asc_build_state.py を手元に置いておくと、次に止まったときの1時間の過ごし方が変わるかもしれません。同じところで足止めされている方の、最短の抜け道になれば幸いです。