◉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中級

環境変数を変えて Android をビルドし直したのに、アプリが前の接続先のままです。「UP-TO-DATE」と出た行を見る

EXPO_PUBLIC_ の値だけを変えて Android のリリースビルドを回すと、バンドルのタスクが UP-TO-DATE で飛ばされ、前の値が残る件です。最小の Gradle で同じ動きを再現し、見分け方と、直るまでの逃げ道を整理します。

Expo229Android63Gradle4環境変数12EXPO_PUBLIC4トラブルシューティング100SDK 573

開発用の API を向いたまま、本番用のビルドを作ってしまった——その可能性に気づくきっかけは、アプリの挙動ではなく、ビルドログのたった1行でした。

> Task :app:createBundleReleaseJsAndAssets UP-TO-DATE

環境変数の EXPO_PUBLIC_API_URL を本番の値に変え、Android のリリースビルドをやり直したとします。ビルドは「BUILD SUCCESSFUL」で終わります。ところが、できたアプリの中身は、前回の開発用の値のままかもしれません。Expo の GitHub に、まさにこの症状の報告が上がっておりました。

最初にお伝えしたいのは、結論です。値だけを変えたビルドは、Gradle から見ると「何も変わっていないビルド」で、JavaScript のバンドルを作り直さずに飛ばすことがあります。 以下、確認できたことと、私が手元で再現した範囲を分けて書き残します。

症状の見分け方

報告されている条件は、はっきりしています。

確かめることこの結果なら
変えたのは環境変数や .env の値だけか(JavaScript のソースは触っていない)該当します。ソースが同じだと、Gradle は入力が変わっていないと判断します
ビルドログに `createBundleReleaseJsAndAssets UP-TO-DATE` が出ているか出ているなら、バンドルは作り直されていません
同じ `android` フォルダで、続けてビルドしているか前回の出力が残っているときに起きます。真っさらな環境では起きにくいはずですが、報告では確認されていません
値を `EXPO_PUBLIC_` で始めているかこの接頭辞の値は、ビルド時にバンドルへ埋め込まれます。アプリを実行するときに読まれるのではありません

報告は expo/expo の Issue 49630 です。2026年9月1日に立ち、SDK 57・React Native 0.86・macOS・素の Android プロジェクト(bare workflow)で確認されています。同じ Issue には Expo 側の自動検証も付いており、「再現した」と書かれています。さらに、シェルの環境変数だけでなく、.env ファイルを書き換えた場合も同じだったそうです。

なぜ飛ばされるのか

EXPO_PUBLIC_ で始まる値は、実行時ではなく、バンドルを作るときに文字列として埋め込まれます。つまり、値が変われば、バンドルの中身も変わるはずです。

ところが Gradle は、タスクに「入力」として教えられたものしか見ていません。バンドルを作るタスクの入力は、JavaScript のソースとバンドルの設定です。バンドラが読みに行く環境変数は、その一覧に入っていません。入力も出力も前回と同じに見えるので、Gradle は「やる必要はありません」と判断し、UP-TO-DATE と表示して終わります。

要するに、バンドラの側は環境変数に依存しているのに、Gradle の側はそれを知らない——この食い違いが原因です。

最小のかたちで再現してみる

報告を読むだけでは、手応えがありません。そこで、Android も Expo も使わず、Gradle だけで同じ食い違いを作ってみました。バンドルを作るタスクを真似て、入力は src フォルダだけ、出力は1ファイル、中身は環境変数から埋め込みます。

tasks.register('createBundle') {
  inputs.dir('src')                                   // 入力: ソースだけ
  outputs.file(layout.buildDirectory.file('index.bundle'))
  doLast {
    def out = layout.buildDirectory.file('index.bundle').get().asFile
    out.parentFile.mkdirs()
    // バンドラが環境変数を埋め込む動作の代わり
    out.text = "var API = '" + (System.getenv('EXPO_PUBLIC_API_URL') ?: '') + "';\n"
  }
}

値を変えて2回回した結果は、次のとおりです(Gradle 8.14.3)。

# 1回目: EXPO_PUBLIC_API_URL=https://dev.example.invalid
> Task :createBundle
var API = 'https://dev.example.invalid';

# 2回目: EXPO_PUBLIC_API_URL=https://prod.example.invalid
> Task :createBundle UP-TO-DATE
var API = 'https://dev.example.invalid';

2回目は UP-TO-DATE になり、出力は開発用の値のままでした。ビルドは成功扱いなので、ログを流し読みしていると、まず気づけません。

直し方:環境変数を「入力」として宣言する

報告者が示している対処は、EXPO_PUBLIC_ で始まる環境変数を、バンドルのタスクの入力として Gradle に教える方法です。私の最小の例にも、同じ考え方で1行足してみました。

def pub = providers.environmentVariablesPrefixedBy('EXPO_PUBLIC_')
tasks.named('createBundle') { inputs.property('expoPublicEnv', pub) }

宣言を足したうえで、同じ順に3回回しました。

# 1回目: dev の値
> Task :createBundle                 → https://dev.example.invalid
# 2回目: prod の値
> Task :createBundle                 → https://prod.example.invalid
# 3回目: prod の値のまま
> Task :createBundle UP-TO-DATE

値が変わった2回目は再実行され、変わらない3回目だけが飛ばされました。これなら、速さを保ったまま、値の取り違えも防げます。

ここで、確認していないことを分けておきます。上の動きは、あくまで私が作った最小の模型の結果です。実際の Expo のプロジェクトでは、報告された書き方(createBundle で始まり JsAndAssets で終わるタスクに対して入力を足す)を使います。私は手元の Android 実機とプロジェクトでは試していません。

直るまでの逃げ道

Expo 側では、この入力を自動で宣言する修正が、Pull Request 49839 として出されています。私が確認した10月27日の時点では、まだ取り込まれていませんでした。直るまでの間は、次のどれかで凌ぐことになります。

  • 値を変えたビルドでは、--rerun-tasks を付けて、すべてのタスクを強制的に実行し直します。確実ですが、ビルド全体が遅くなります。
  • 上の宣言を、Android 側のビルド設定に書き足します。ただし、android フォルダを毎回作り直す運用の方は、書き足した内容が消えます。
  • 本番用のビルドは、前回の出力が残っていない環境(きれいに取得し直した状態)で作ります。

EAS のクラウドビルドでも起きるのかどうかは、報告でも「未確認」の扱いでした。私も確かめておりませんので、断定はいたしません。

本番に出す前の、ひと手間

結局のところ、いちばん確実なのは「できあがったものの中身を見る」ことだと思います。ビルドが成功した事実と、狙った値が入っている事実は、別のものです。リリース用のファイルができたら、開発用の接続先の文字列が入っていないかを、公開の前に1度だけ探してみてください。

成功の表示は、中身の保証ではありません。 この線引きを忘れかけた日は、ログの UP-TO-DATE を探すところから確かめ直すようにしています。

なお、デプロイのあとに古い状態が残り続けるという点では、Web 側にも似た落とし穴があります。そちらは デプロイ直後に出る Application error は、なぜ再デプロイでは直らないのか で、原因の側から掘り下げております。

次にビルドの接続先を切り替えるときは、まずビルドログを開いて、createBundle の行が UP-TO-DATE になっていないかだけ、確かめていただければと思います。

シェア

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

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

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

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

関連記事

◇ アプリ開発2026-10-15
EAS Build だけ「No matching variant」で落ちるとき、まず疑う手元の android/build
手元の Gradle は通るのに、EAS Build の Android だけが「No matching variant of project」で止まる。GitHub の報告を読み比べ、Windows で生成した autolinking のキャッシュが Linux のビルド機へ渡っていた経路と、ビルドを投げる前に確かめる診断スクリプトをまとめました。
◇ アプリ開発2026-10-21
iOS では動く expo-widgets が Android のビルドだけで落ちる — 版の固定と除外、どちらで逃げるかの判断
expo-widgets を 58.0.17 以降に上げると Android だけ Kotlin のコンパイルで止まる報告があります。症状の見分け方、版の固定と autolinking 除外の使い分け、手元で判定できる確認スクリプトをまとめました。
◇ アプリ開発2026-10-18
debug では動くのに、release の起動だけ「見つからない」で落ちました。名前の文字列で引いていた資源が、縮小で消えていたためです
release ビルドだけ、起動時に資源が見つからず落ちる。原因は、名前の文字列で引いていた画像や音がリソース縮小で消えていたことでした。keep.xml を prebuild で書き出す設定と、ビルド後に確かめる検査を組みました。