◉RORK LABEN
●EXPO — EAS Observe がネイティブクラッシュも記録(10/07)。JavaScript エラーと並べて確認できます●SDK 58 — SDK 58 Beta は 9/15 公開。stable の日付はまだ未確認です●RN 0.88 — React Native 0.88.x の正式リリース予定は 10/12、残り4日●Q&A — expo-widgets が本番ビルドだけ真っ黒になる、という問いが出ています●RORK — 09-29 に GPT-6.1 Sol を追加。Pro・Max プランで利用できます●NEW — 日本語の見出しだけ太字にならない Android の切り分け●EXPO — EAS Observe がネイティブクラッシュも記録(10/07)。JavaScript エラーと並べて確認できます●SDK 58 — SDK 58 Beta は 9/15 公開。stable の日付はまだ未確認です●RN 0.88 — React Native 0.88.x の正式リリース予定は 10/12、残り4日●Q&A — expo-widgets が本番ビルドだけ真っ黒になる、という問いが出ています●RORK — 09-29 に GPT-6.1 Sol を追加。Pro・Max プランで利用できます●NEW — 日本語の見出しだけ太字にならない Android の切り分け
記事一覧/アプリ開発
◇ アプリ開発/2026-08-24上級

サムネイルの移設は、配信中の版が旧パスを要求し続ける前提で組みました

サーバー側で画像の置き場所を変えても、ストアで配信中の版はビルド時のパス組み立てを持ち続けます。旧新どちらのパスでも 200 を返す双方向フォールバック、画像とカタログの更新順序、CDN を挟んだまま実応答を確かめる手順を、壁紙アプリの運用で使っている形のまま共有します。

アセット配信3壁紙アプリ28Expo213運用設計8CDN

✦ プレミアム記事

6.5 インチ用に作り直したサムネイルを本ツリーへ移し終えて、あとはアップロードするだけ、というところで手が止まりました。

置き場所のディレクトリ名を変えたということは、いま App Store で配信されている版が組み立てる URL と、明日からサーバーに実体がある場所とが食い違う、ということです。手元のシミュレータでは最新のコードが動いていますので、この食い違いは開発中に一度も表へ出てきません。

個人開発で壁紙系のアプリを長く運用していると、この種の「サーバー側だけを整理する作業」が定期的に発生します。画像を1枚増やすたびに審査へ出すわけにはいきませんので、配信の実体はサーバー側へ寄せてあります。その結果、サーバーのディレクトリ構成を触る自由と、配信済みの版が焼き込んだ前提とが、正面からぶつかります。

移設そのものは10分で終わります。難しいのは、移設したあとで何を確認できたら「反映できた」と言い切ってよいのか、という部分でした。

配信済みの版が持ち続けるのは、画像ではなくパスの組み立て規則

リモート配信に切り替えたアプリがバイナリに持っているのは、画像そのものではありません。持っているのは、ID から URL を組み立てる規則です。

// 配信中の版(iOS 4.1.1)が持っている組み立て規則
const STORAGE_BASE = "https://storage.example.net";
const THUMB_DIR = "5_8inch/thumb_full";   // ビルド時に決まる
 
export function thumbUrl(app: string, id: number) {
  return `${STORAGE_BASE}/ios/wallpaper_apps/${app}/${THUMB_DIR}/${id}.jpg`;
}

この THUMB_DIR は、ユーザーの端末に入っている版が更新されるまで一文字も変わりません。サーバー側で 6_5inch/thumb_full/ へ移した瞬間から、配信中の版は存在しない場所を叩き続けます。

見落としやすいのは、この規則がアプリのバージョンごとに違うという点です。私が運用している壁紙アプリでは、iOS と Android で世代が揃っていません。iOS 側は 4.1.1、Android 側は 1.9.0 が主力で、それぞれ別のディレクトリ規約を持って出荷されています。移設の影響範囲は「アプリが何本あるか」ではなく、「いま実際に使われているバージョンが何種類あるか」で決まります。

ストア側の管理画面でバージョン別のアクティブ端末数を見ると、リリースから半年が経った版がまだ二桁パーセント残っていることは珍しくありません。自動更新をオフにしている方、通信環境の都合で更新が進まない端末、機種変更後に古いバックアップから復元された端末。旧パスは、こちらが移設を終えた翌日に消えてくれるものではありません。

リモート設定を入れても、効くのは「入れた版から」です

最初に考えたのは、THUMB_DIR をリモート設定から受け取る形へ直すことでした。

type RemoteConfig = { thumbDir?: string };
 
export async function loadThumbDir(): Promise<string> {
  try {
    const res = await fetch(`${API_BASE}/ios/wallpaper_apps/${app}/config.json`, {
      cache: "no-store",
    });
    const cfg = (await res.json()) as RemoteConfig;
    return cfg.thumbDir ?? "6_5inch/thumb_full";   // 取得できなければ現行既定
  } catch {
    return "6_5inch/thumb_full";                    // 通信不能でも組み立ては続ける
  }
}

設計としては素直です。ただ、これを入れても救えるのは「これを入れた版から先」だけでした。いま困っているのは、この分岐を持っていない版です。

ここが、私が最初に取り違えていた部分でした。リモート設定は将来の自由度を買う仕組みであって、過去に出荷した版へさかのぼって効くものではありません。過去に出した版を救えるのは、サーバー側の応答だけです。

同じ理由で、config.json のフォールバック既定値を固定文字列で書くのも避けています。既定値が実際の総数や置き場所とずれると、通信に失敗した端末だけが古い世界を見ることになります。配信中の総数を返す処理は、固定文字列をやめて同じ変数から組み立てる形へ直してあります。

✦

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

この記事の続きを読む

この先には、実装コードやベンチマーク結果など、実務でお役に立てる内容をご用意しています。このサイトは広告を掲載しておらず、サーバーや開発にかかる費用はメンバーの皆様のご支援で成り立っています。もしお役に立てていましたら、ご支援いただけますと大変ありがたいです。

この記事で得られること
✦配信済みの版が何を前提にしているかを棚卸しして、サーバー側の整理をいつ・どの順で始めてよいかを自分で判断できるようになります
✦旧パスへのリクエストが残っているうちに移設して、ユーザーの端末でサムネイルだけが欠けるという事故を未然に防げるようになります
✦画像は上がっているのに一覧の総数が古い、という中途半端な反映を、CDN を挟んだまま4か所の実応答で数分のうちに切り分けられるようになります
Stripe による安全な決済 · いつでもキャンセル可能
✦

この記事を購入する

この先の内容をすべてお読みいただけます。一度のご購入で、いつでも何度でもアクセスできます。このサイトは広告を掲載しておらず、皆さまのご支援がサーバー費用などの運営を支えています。

または
メンバーシップなら全記事が読み放題 →
シェア

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

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

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

関連記事

◇ アプリ開発2026-09-23
落ちたはずなのに「固まる」と書かれる — Android のクラッシュが白い画面のまま残るとき
クラッシュレポートには例外が並ぶのに、利用者からは「固まる」としか報告されないことがあります。expo-updates と新アーキテクチャの組み合わせで Android の画面が白いまま残る仕組みと、復帰導線・異常終了の検知・原因の特定を順番に置いていく手順をまとめます。
◇ アプリ開発2026-09-18
prebuild が requires the standard Expo SDK 57 Swift AppDelegate で止まったとき、まず確かめる3行
iOS 27 のために ios.enableSceneSupport を有効にすると prebuild が止まることがあります。原因は SDK の版ではなく AppDelegate.swift の形でした。確かめる3行と、手で書くときに SDK 58 の手順を真似てはいけない理由をまとめます。
◇ アプリ開発2026-09-16
消したはずのトークンが再起動で戻る — SecureStore の削除失敗を検知する設計
サインアウト直後に getItemAsync が null を返しても、Android のディスクには値が残っていることがあります。削除の成否を読み出しで確かめていた実装を、戻り値で判断する形へ書き直した記録です。
📚RECOMMENDED BOOKS
大規模言語モデル入門
山田育矢
LLM開発
生成AIプロンプトエンジニアリング入門
我妻幸長
プロンプト
Claude CodeによるAI駆動開発入門
平川知秀
AI駆動開発
※ アフィリエイトリンクを含みます