◉RORK LABJP
●GPT-6.1 SOL — Added to Rork's model menu (09-29) with Low, Medium and High effort; included on Pro and Max●SONNET 5.5 — Claude Sonnet 5.5 is selectable: strong at UI design and faster than Sonnet 5 (09-28)●SONNET 4.5 — Retires on the Claude API on 11/30, 27 days left. If your app calls it, check the migration target●SDK 58 — Moves to React Native 0.88. R8 is now on by default in Android release builds, and iOS prebuild generates a SceneDelegate●OBSERVE — EAS Observe now records native crashes too (SDK 57.0.21 or later, 10/07)●NEW — My App Open Ad Only Showed When the App…●GPT-6.1 SOL — Added to Rork's model menu (09-29) with Low, Medium and High effort; included on Pro and Max●SONNET 5.5 — Claude Sonnet 5.5 is selectable: strong at UI design and faster than Sonnet 5 (09-28)●SONNET 4.5 — Retires on the Claude API on 11/30, 27 days left. If your app calls it, check the migration target●SDK 58 — Moves to React Native 0.88. R8 is now on by default in Android release builds, and iOS prebuild generates a SceneDelegate●OBSERVE — EAS Observe now records native crashes too (SDK 57.0.21 or later, 10/07)●NEW — My App Open Ad Only Showed When the App…
Articles/App Dev
◇ App Dev/2026-06-13Advanced

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.

asset deliverywallpaper app23versioningExpo234operations10

✦ Premium Article

Bumping a build, swapping screenshots, and waiting two days for review — just to add ten seasonal wallpapers. That loop worked right after launch. But once I was running six wallpaper apps in parallel, it became a hard bottleneck. While one app sat in review, images piled up for three others, and I kept pushing the whole batch to "next week."

Adding content has nothing to do with app code. The behavior does not change when there are more images. So I moved content delivery outside of app review entirely. What follows is the remote asset pack system I rebuilt, along with the code I run and the transfer numbers I measured before and after the switch.

Why I stopped bundling assets

The first design bundled images inside the app. That guarantees offline display and a fast cold start. The cost is that every new image requires a full re-submission, and the IPA keeps growing. Crossing 90MB after six months was the breaking point.

I narrowed the decision to two axes. The first is update frequency: content swapped several times a week goes remote, while UI assets fixed at release stay bundled. The second is first-run experience: the handful of images guaranteed to appear on launch (the default cover, onboarding art) stay bundled, and everything else is fetched remotely. That line let me fix the bundled set at about twenty images.

A manifest-first approach — what to deliver, what to delete

The center of remote delivery is not the images but the manifest. On launch the app fetches the manifest first, then retrieves images according to its instructions. The schema looks like this.

{
  "packVersion": 142,
  "minAppVersion": "3.2.0",
  "generatedAt": "2026-06-13T02:00:00Z",
  "categories": [
    {
      "id": "seasonal-rainy",
      "title": { "ja": "雨の季節", "en": "Rainy Season" },
      "items": [
        {
          "id": "rainy-0142",
          "hash": "b7f3c1a9",
          "w": 1290, "h": 2796,
          "url": "https://cdn.example.com/packs/rainy-0142.heic",
          "thumb": "https://cdn.example.com/thumbs/rainy-0142.webp",
          "addedIn": 142
        }
      ]
    }
  ]
}

The key fields are hash and addedIn. The hash is a short fingerprint derived from the image content, and we only refetch when it changes. The addedIn value records the pack version where an image first appeared, which drives delta computation. The minAppVersion is a safety valve that keeps a newer image format (a live wallpaper added later, say) from reaching older apps.

The manifest itself lives at the CDN edge with Cache-Control: max-age=300 — five minutes. I keep it short so that pulling a single bad image propagates to every device within five minutes at most. Image bodies never change once published, so they get max-age=31536000, immutable for a one-year cache.

✦

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
✦A concrete manifest schema that decouples content packs from App Store review so delivery becomes instant
✦A delta-download implementation that cut transfer per update by 88% on average by avoiding full refetches
✦Version-pinning and a rollback procedure that reverts a broken pack in 30 seconds across all six apps
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 $10 for lifetime access
View Membership →

Related Articles

◇ App Dev2026-08-24
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.
◇ App Dev2026-10-29
An Image Requested Once Before Its Upload Stayed a 404 at the Edge. I Split the Retention Rules by Status Code and Made Upload and Purge a Single Step
A new wallpaper stayed missing in some regions because the CDN kept a 404, fetched once before the upload, as long as it kept the image itself. Per-status retention, a two-request diagnosis, and pairing upload with purge, tested in Node.
◇ App Dev2026-10-31
When EAS Build Stops at "Project archive is too big", Count What Gets Uploaded, Largest First
EAS Build warns at 150 MiB and fails at 2 GiB. Here is how to list what will be uploaded before you send it, find the culprit, and decide what goes into .easignore.