RORK LABJP
DEADLINE — From August 31, every new app and update on Google Play must target Android 16 (API level 36). Seven days to goEXTENSION — If you qualify, you can request an extension through November 1 using a form in Play Console, but the request itself has to be filed before the deadlineMAX — Rork Max generates native Swift rather than React Native and compiles on a cloud Mac fleet, covering iPhone, iPad, Apple Watch, Apple TV, Vision Pro, and iMessageCOMPANION — The Rork Companion app lets you test on a real iPhone without a paid Apple Developer account, so design, build, and test can all happen in a browserDEVTOOLS — React Native DevTools in Expo SDK 57 can emulate light and dark mode, letting you check both appearances without touching device settingsIOS27 — iOS 27 ships next month. Beta 6 landed on August 17, and RCS Universal Profile 3.0 support means you can finally reply to a specific message received from AndroidDEADLINE — From August 31, every new app and update on Google Play must target Android 16 (API level 36). Seven days to goEXTENSION — If you qualify, you can request an extension through November 1 using a form in Play Console, but the request itself has to be filed before the deadlineMAX — Rork Max generates native Swift rather than React Native and compiles on a cloud Mac fleet, covering iPhone, iPad, Apple Watch, Apple TV, Vision Pro, and iMessageCOMPANION — The Rork Companion app lets you test on a real iPhone without a paid Apple Developer account, so design, build, and test can all happen in a browserDEVTOOLS — React Native DevTools in Expo SDK 57 can emulate light and dark mode, letting you check both appearances without touching device settingsIOS27 — iOS 27 ships next month. Beta 6 landed on August 17, and RCS Universal Profile 3.0 support means you can finally reply to a specific message received from Android
Articles/App Dev
App Dev/2026-08-24Advanced

I Moved the Thumbnails Assuming the Shipped Build Would Keep Asking for the Old Path

Reorganizing image directories on the server does not reach the builds already installed on people's phones. Here is the two-way fallback that returns 200 for both the old and new paths, the ordering rule for images versus catalog, and the four checks I run through a CDN before calling a release live.

asset delivery2wallpaper apps3Expo181operations8CDN2

Premium Article

The new 6.5-inch thumbnails were generated, verified, and moved into the master tree. All that was left was the upload. That is where I stopped.

Renaming the directory meant that the URL the currently shipped iOS build assembles and the place where the files would actually live from tomorrow were about to disagree. On my machine the simulator runs the newest code, so this disagreement never surfaces during development. It only exists on other people's phones.

Running wallpaper apps as an indie developer for as long as I have, this kind of "server-side only" cleanup comes up regularly. You cannot push a build through App Store review every time you add a single image, so the actual content lives on the server. The price of that freedom is that every directory you rename collides with an assumption some shipped build baked in months ago.

The move itself takes ten minutes. The hard part was deciding what evidence would let me say the release had actually landed.

What a shipped build holds is not the image — it is the rule that builds the URL

An app that delivers its content remotely does not carry the images. It carries a function from ID to URL.

// The rule the currently shipped build (iOS 4.1.1) carries
const STORAGE_BASE = "https://storage.example.net";
const THUMB_DIR = "5_8inch/thumb_full";   // frozen at build time
 
export function thumbUrl(app: string, id: number) {
  return `${STORAGE_BASE}/ios/wallpaper_apps/${app}/${THUMB_DIR}/${id}.jpg`;
}

THUMB_DIR will not change by a single character until that device installs a newer build. The moment the files move to 6_5inch/thumb_full/, every shipped build keeps knocking on a door that is no longer there.

The part that is easy to miss: this rule differs per version, not per app. Across my wallpaper apps the iOS and Android lines are not in sync — iOS is mostly on 4.1.1 while Android sits on 1.9.0, and each shipped with its own directory convention. The blast radius of a move is not "how many apps do I have"; it is "how many distinct versions are still in active use."

Open the version breakdown in the store console and you will usually find a build from six months ago still holding a double-digit share. People who turned off automatic updates. Devices on metered connections. Phones restored from an old backup after an upgrade. The old path does not disappear the day after you finish moving files.

Remote config only helps from the build that contains it

My first instinct was to make THUMB_DIR come from remote config.

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";   // current default
  } catch {
    return "6_5inch/thumb_full";                    // keep building URLs offline
  }
}

Clean enough. But it rescues exactly one population: builds shipped after the change. The builds giving me trouble are the ones without this branch.

That was my own mistake, stated plainly. Remote config buys future flexibility; it does not travel backwards into binaries you already shipped. The only thing that can reach those binaries is the response your server sends.

For the same reason I stopped hard-coding fallback constants such as the catalog total. When a fallback literal drifts away from the real value, the devices that failed to reach the network are the only ones living in the stale world — which is precisely the population you cannot debug. Those responses are now assembled from the same variable the live endpoint uses.

Thank you for reading this far.

Continue Reading

What follows includes implementation code, benchmarks, and practical content we hope you'll find useful. This site runs without ads — server and development costs are supported entirely by members like you. If it's been helpful, we'd be truly grateful for your support.

WHAT YOU'LL LEARN
You will be able to inventory what your already-shipped builds assume, and decide for yourself when it is safe to start reorganizing anything on the server
You will be able to move assets while old-path traffic is still arriving, without users ever seeing a screen full of missing thumbnails
You will be able to tell within minutes whether a release is half-applied — images uploaded, catalog still stale — even with a CDN sitting in front of everything
Secure payment via Stripe · Cancel anytime

Unlock This Article

Get full access to the rest of this article. Buy once, read anytime. This site is ad-free — your support goes directly toward keeping it running.

or
Unlock all articles with Membership →
Share

Thank You for Reading

Rork Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • Copy-paste ready implementation code
  • New advanced guides published daily
  • $5/mo or $15 for lifetime access
View Membership →

Related Articles

App Dev2026-06-13
Shipping Wallpaper Packs Without an App Review — Versioning and Delta Delivery for Remote Assets Across Six Apps
Re-submitting your app every time you add ten wallpapers grinds operations to a halt. Here is a manifest-based versioning scheme with delta downloads, cache invalidation, and rollback — with the implementation and measured transfer savings from running six apps in parallel.
App Dev2026-05-29
Three Weeks of Syncing Release Notes Across Six Wallpaper Apps
Notes from three weeks of writing What's New entries for six wallpaper apps in the same week, with the same tone, using Rork as the source of truth.
App Dev2026-08-23
Bumping targetSdk to 36 surfaced a 16 KB warning. These are two different deadlines
The August 31 target API 36 requirement and the February 1, 2027 16 KB page size requirement are separate conditions. Here is how to inspect your AAB without installing the NDK, and why a LOAD misalignment and a zip boundary miss need completely different fixes.
📚RECOMMENDED BOOKS
Build a Large Language Model (From Scratch)
Sebastian Raschka
LLM Dev
Prompt Engineering for LLMs
Berryman & Ziegler
Prompting
AI Engineering
Chip Huyen
AI Eng
* Contains affiliate links
See all →