◉RORK LABEN
●GPT-6.1 SOL — Rork のモデルメニューに追加(09-29)。Low/Medium/High を選べ、Pro・Max に含まれます●SONNET 5.5 — UI づくりが得意で、Sonnet 5 より出力が速いモデルが選べます(09-28)●SONNET 4.5 — Claude API での提供終了は 11/30、残り34日。API 連携を足したアプリは移行先の確認を●SDK 58 ISSUE — Android ウィジェットが定期更新されない、Stripe が静的リンクになるなど初期報告が出ています●OBSERVE — EAS Observe がネイティブクラッシュも記録します(SDK 57.0.21 以降・10/07)●NEW — 起動広告が、背面から戻った回にしか出ていませんでした。「前面に戻った」合図が、…●GPT-6.1 SOL — Rork のモデルメニューに追加(09-29)。Low/Medium/High を選べ、Pro・Max に含まれます●SONNET 5.5 — UI づくりが得意で、Sonnet 5 より出力が速いモデルが選べます(09-28)●SONNET 4.5 — Claude API での提供終了は 11/30、残り34日。API 連携を足したアプリは移行先の確認を●SDK 58 ISSUE — Android ウィジェットが定期更新されない、Stripe が静的リンクになるなど初期報告が出ています●OBSERVE — EAS Observe がネイティブクラッシュも記録します(SDK 57.0.21 以降・10/07)●NEW — 起動広告が、背面から戻った回にしか出ていませんでした。「前面に戻った」合図が、…
記事一覧/開発ツール
⬡ 開発ツール/2026-10-27中級

iPhone の Expo Go では開くのに、Android だけ「Failed to download remote update」で止まります。サインイン済みでも 403 になる経路

EAS Update が iOS の Expo Go では開き、Android の Expo Go(SDK 57)だけ Failed to download remote update で止まる件です。原因はサインイン情報の保存先と読み出し先のずれで、修正は SDK 58 側にあります。切り分けの順番と、手元で確かめる手順をまとめました。

Rork603Expo Go6EAS Update8Android62トラブルシューティング99SDK 57

EAS Update を配信して、ダッシュボードの QR コードを iPhone の Expo Go で読むと、アプリが開きます。同じ QR コードを Android の Expo Go で読むと、赤い画面に1行だけ出て止まります。最初に見たとき、私なら更新データのほうを疑っていたと思います。

Uncaught Error: java.io.IOException: Failed to download remote update

「View error log」を開いても、中身はこの1行のままです。HTTP のステータスも、取れなかったアセットの名前も書かれていません。更新データを作り直し、キャッシュを消し、Expo Go を入れ直したあとで、もう一度同じ画面に戻ってくる——そういう夜を過ごしている方に向けて、報告されている原因と、手元での切り分けの順番を書き残します。

先に線を引きます。疑うのは更新データではなく Expo Go の側です

私も壁紙アプリを iOS と Android の両方で出しているので、片方だけ結果が違うと、まず自分の設定を疑う癖がついています。その癖に気づいたのは、同じ確認を何度も繰り返したあとでした。今回はその癖が裏目に出る種類の不具合でした。

Expo の GitHub に、まさにこの症状の報告があります(expo/expo#50139)。create-expo-app の空のテンプレートに expo-updates を足しただけの SDK 57 プロジェクトで、同じ更新グループが iOS では開き、Android 実機2台では開かなかったという内容です。依存は5つで、アセットは1つだけです。プロジェクト側に疑う余地がほとんど残っていません。

そこで、最初の切り分けは次の4点を、この順に見ます。

確かめることこの結果なら
同じ更新が iOS の Expo Go で開くか開くなら、更新データ自体は健全です。Android だけの経路を疑います
Android が実機か、エミュレータかエミュレータで開き、実機だけ開かないなら、今回の件に当てはまります
Expo Go のバージョンSDK 57 向けの 57.0.9 で報告されています。58 系は後述のとおり事情が違います
サーバーが返す HTTP ステータス403 なら、読み込みの手前で弾かれています。404 なら、そもそも更新グループかランタイム版が違います

最初の2行が「はい」なら、アセットや bundle を疑う前に、Expo Go が送っているリクエストの中身を疑う段階に入ってよいと思います。

原因は、サインインの情報が2か所に分かれていたことです

もう一つの報告(expo/expo#50253)が、ソースの該当行まで辿っています。要点は次のとおりです。

Android の Expo Go では、ホーム画面の作り直しのあと、サインインの秘密情報が expo_session という保存先に書かれるようになりました。ところが更新を読み込む側は、古い expo_auth_session という保存先を読み続けていました。後者を書き込んでいたのは、作り直しで消えた旧ホーム画面だけです。

その結果、プロフィールからサインインすると、ホーム画面にはプロジェクトとブランチの一覧がきちんと並びます。画面の上では認証されています。ところが、マニフェストとアセットを取りに行くリクエストには Expo-Session ヘッダーが付かないまま出ていきます。

サーバーが返すのは、報告によれば次の403です。

403: Experience "@owner/slug" is not viewable in Expo Go: this project requires authentication.
Sign in to Expo Go with an Expo account that is a member of the account that owns this project.

サインインしたあとで同じリンクを開き直しても、約0.6秒で同じ失敗が返ってくる、と報告者は書いています。修正の PR(expo/expo#50498)の説明には、この食い違いが長く見えなかった理由も添えられていました。サーバーがもともと所有者の確認を求めていなかったことと、エミュレータは EXPO_SIMULATOR として名乗るため、サーバーが確認の対象にしていないことの二つです。エミュレータでは動き、実機でだけ落ちる、という症状の説明にもなっています。

画面の上でサインインできていることと、読み込みが同じ鍵を見ていることは、別の話でした。

手元で確かめる2つの手順

一つめは、更新グループそのものがサーバーに見えているかを、プラットフォームごとに確かめる小さなスクリプトです。Expo Go を通さず、同じ URL に curl で問い合わせます。

#!/usr/bin/env bash
# 使い方: ./manifest_probe.sh <projectId> <groupId> <SDK のメジャー番号>
set -euo pipefail
PID="${1:?projectId}"; GID="${2:?groupId}"; SDK="${3:?sdk major}"
URL="https://u.expo.dev/${PID}/group/${GID}"
for P in ios android; do
  CODE=$(curl -sS -m 20 -o "/tmp/probe_${P}.txt" -w '%{http_code}' "$URL" \
    -H "expo-platform: ${P}" \
    -H "expo-runtime-version: exposdk:${SDK}.0.0" \
    -H "accept: multipart/mixed")
  echo "${P}: HTTP ${CODE}"; head -c 300 "/tmp/probe_${P}.txt"; echo
done

存在しない ID を渡して回したときの出力は、次のとおりでした。

ios: HTTP 404
There is no update identified by group ID "11111111-1111-4111-8111-111111111111" and platform "ios"
android: HTTP 404
There is no update identified by group ID "11111111-1111-4111-8111-111111111111" and platform "android"

読み方は単純です。両方が200なら、更新データはサーバー上で両プラットフォーム分そろっています。片方だけ404なら、そのプラットフォーム向けの eas update が通っていません。ここが両方そろっているのに Android の Expo Go だけ落ちるなら、更新データの問題ではなく、Expo Go が送るリクエストの問題です。なお、このスクリプトは Expo Go のサインイン情報を持たないので、403 を再現するためのものではありません。更新グループの有無とランタイム版の取り違えを先に除くための道具です。

二つめは、Android 実機で Expo Go のバージョンと、失敗の行を拾う手順です。

# Expo Go の版を確認し、読み込み失敗の行だけを拾う
adb shell dumpsys package host.exp.exponent | grep versionName
adb logcat -d | grep -i "Remote update request not successful"

この行がログに出ていれば、サーバーがリクエストを受け取ったうえで、2xx 以外を返しています。先ほどの1行エラーに欠けていた「非2xx だった」という事実が、ここで初めて確かめられます。ただし、このコマンドは私の手元に Android 実機がないため実行しておらず、報告の記述に沿って書いたものです。

直るのはいつか。確認できた範囲だけを書きます

修正の PR は 2026-09-23 に main へ取り込まれました。この日付は、PR の状態から読み取った値です。そのうえで、ソースを実際に見比べた結果をお伝えします。

ブランチ更新ヘッダーの読み出し元
sdk-57旧保存先(`exponentSharedPreferences.sessionSecret`)のまま
sdk-58新しい保存先(`sessionRepository`)を読む形に変更済み

SDK 57 向けの最後の Expo Go は 57.0.9(2026-08-15 公開)で、それより新しい 57 系のビルドは確認できませんでした。つまり、SDK 57 のまま Android の Expo Go で、所有者の確認が要る更新を開く経路は、今のところ直っていないと読めます。58 系の Expo Go(58.0.7 が 2026-10-24 公開)は、ソース上は修正を含んでいます。ただ、ストアから入る 58 系のビルドで実機の動作を確かめたわけではありません。ここは、確かめた範囲と確かめていない範囲を分けて書いておきます。

その間の逃げ道は、どれも「Expo Go の読み込み経路を通らない」か「通る経路を変える」ものです。

  • iOS の Expo Go で確認します。報告でも、同じ更新が iOS では開いています。
  • Android のエミュレータで確認します。PR の説明によれば、エミュレータはサーバーの確認の対象外です。
  • Expo Go ではなく、自分でビルドしたアプリ(development build や内部配布のビルド)に更新を当てて確認します。不具合は Expo Go の更新ローダーの中にあるため、この経路は通りません。
  • SDK 58 へ上げたうえで、58 系の Expo Go で試します。移行の量が大きいので、このためだけに上げるのは勧めません。

どれを選ぶかは、お手元の状況しだいです。ひとまず「更新データは壊れていない」と分かっただけで、作り直しと再配信の往復は止められます。

更新が反映されない別のパターンを切り分けたい方は、EAS Update を配信したのに反映されないときの5つの典型パターン もあわせてご覧ください。Expo Go 側のログインそのものを確かめる順番は、Expo Go がプレビューを開かなくなった日に最初に確かめる2つのログイン に書いてあります。

次に Android だけが違う結果を返したら、更新データを作り直す前に、iOS で開くかどうかと、実機かエミュレータかの2点を確かめてみていただければと思います。この2点は、片方のプラットフォームだけ結果が違うときの確認手順の先頭に置いておこうと、いまは考えています。

シェア

お読みいただきありがとうございます

Rork Lab は広告なしで運営しており、サーバー費用などの運営コストはメンバーシップのご支援で賄っています。実装コード・ベンチマーク・本番設計パターンなど、実務でお役立ていただける記事を毎日更新しています。もし読んでよかったと感じていただけましたら、ぜひご覧ください。

  • ✦コピー&ペーストで使える実装コード付き
  • ✦毎日新しい上級ガイドを追加
  • ✦¥580/月 または ¥1,480 の永久アクセス
メンバーシップを見る →

もしこの記事がお役に立ちましたら、チップ(¥150)で応援いただけると大変励みになります。広告なしでの運営を続けるため、皆さまのご支援が大きな力になっています。

関連記事

⬡ 開発ツール2026-10-07
日本語の見出しだけ太字にならない — Android で fontWeight が効かないときの切り分けと直し方
Rork で作ったアプリで、iPhone では太字なのに Android では日本語の見出しが細いままになる症状の切り分け記事です。原因の見分け方、fontFamily を重みごとに分ける直し方、確認用コードを載せています。
⬡ 開発ツール2026-10-25
効果音が40回目で鳴らなくなる——expo-audio の createAudioPlayer は remove() だけでは片づきません
expo-audio で再生のたびに createAudioPlayer を作ると、Android では約40回で音が止まり、didJustFinish も届かなくなります。remove() と release() の役割の違い、作り方を変える三つの選択肢、止まったときの見張り方を整理します。
⬡ 開発ツール2026-10-24
ANR の原因は、画面を閉じるときの「後片付け」でした。トレースから止めている行を拾って分類します
Android の ANR トレースを読み、メインスレッドを止めていた行を課金クライアントの終了や画像の同期デコードなどに分類する Python スクリプトです。壁紙アプリで見つけた二つの原因と、直し方の考え方をまとめました。