RORK LABJP
MAX — Rork Max bills itself as the first web Swift app builder, publishing to the App Store in two clicks with no Xcode requiredAPPLE — It generates native Swift apps for iPhone, iPad, Apple Watch, Apple TV, and Vision ProEXPO — The standard tier builds native iOS and Android apps on React Native (Expo) from a plain-English descriptionFUNDING — Rork raised $2.8M from a16z, strengthening its position in AI no-code mobile developmentPRICE — Free to start, with paid plans from $25/month — an accessible entry point for solo developersWWDC — WWDC 2026 pushes Apple Intelligence forward, raising the value of native features and widening AI integration options for no-code appsMAX — Rork Max bills itself as the first web Swift app builder, publishing to the App Store in two clicks with no Xcode requiredAPPLE — It generates native Swift apps for iPhone, iPad, Apple Watch, Apple TV, and Vision ProEXPO — The standard tier builds native iOS and Android apps on React Native (Expo) from a plain-English descriptionFUNDING — Rork raised $2.8M from a16z, strengthening its position in AI no-code mobile developmentPRICE — Free to start, with paid plans from $25/month — an accessible entry point for solo developersWWDC — WWDC 2026 pushes Apple Intelligence forward, raising the value of native features and widening AI integration options for no-code apps
Articles/Dev Tools
Dev Tools/2026-06-14Advanced

Actually Delivering 'It Updates Without Opening' in Expo — A Realistic Background Task Design

Building 'content refreshes every morning' into a Rork-generated Expo app runs into iOS background execution being far less dutiful than you expect. Here is a minimal expo-background-task setup plus a design that doesn't break when the task never runs.

Rork400Expo72Background TaskBGTaskScheduler3iOS78indie developer25

Premium Article

Running a wallpaper app as an indie developer, the single most requested feature was "I want a new wallpaper every morning without opening the app." Naively, you would just run something periodically in the background and swap the image. But build this seriously on iOS and you end up chasing irreproducible bug reports: "it updated yesterday but not today."

The cause is not a bug in your code — iOS background execution is designed around the premise that you cannot know when it will run. Rork generates an Expo app, but underneath it iOS BGTaskScheduler is at work, and if you build without understanding its capriciousness, your UX is left to chance. This article covers building a refresh experience that survives the task not running, on both the wiring and the judgment side.

Why "It Should Update Every Morning" Doesn't

iOS background tasks are not something you can pin to a clock and force to run. The system runs them only when it decides, based on the device's usage patterns, battery, and network, that "now is acceptable."

So they run fairly often for users who open the app daily, and rarely for users who almost never open it. Ironically, the dormant users who most want "updates without opening" are exactly the ones whose background tasks rarely fire. Accept this asymmetry first or you will design wrong.

A Minimal expo-background-task Setup

Current Expo uses expo-background-task (which uses BGTaskScheduler / WorkManager internally), not the deprecated expo-background-fetch. The task itself is defined with expo-task-manager.

import * as TaskManager from "expo-task-manager";
import * as BackgroundTask from "expo-background-task";
 
const REFRESH_TASK = "daily-wallpaper-refresh";
 
TaskManager.defineTask(REFRESH_TASK, async () => {
  try {
    const updated = await fetchAndCacheTodaysWallpaper();
    // Always return success/failure. Not returning makes iOS shrink your future budget
    return updated
      ? BackgroundTask.BackgroundTaskResult.Success
      : BackgroundTask.BackgroundTaskResult.Failed;
  } catch {
    return BackgroundTask.BackgroundTaskResult.Failed;
  }
});
 
export async function registerRefreshTask() {
  const status = await BackgroundTask.getStatusAsync();
  if (status !== BackgroundTask.BackgroundTaskStatus.Available) return;
  await BackgroundTask.registerTaskAsync(REFRESH_TASK, {
    minimumInterval: 60 * 12, // minutes; 12 hours here
  });
}

In app.json, iOS UIBackgroundModes must include processing. In Expo you write it under infoPlist.

{
  "expo": {
    "ios": {
      "infoPlist": {
        "UIBackgroundModes": ["fetch", "processing"],
        "BGTaskSchedulerPermittedIdentifiers": ["daily-wallpaper-refresh"]
      }
    }
  }
}

Forget to list the task ID in BGTaskSchedulerPermittedIdentifiers and registration succeeds but the task never runs on device — a silent failure. I lost half a day to exactly this.

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
Get a working minimal setup of expo-background-task and expo-task-manager, including the UIBackgroundModes configuration
Understand that minimumInterval is a floor, not a guarantee, expressed through concrete iOS conditions: Low Power Mode, launch frequency, charging state
Implement a two-tier foreground fallback that keeps a wallpaper app's auto-refresh from breaking when background never fires
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

Dev Tools2026-05-28
Tracking Down BGTaskScheduler.submit Error Code=1 (Unavailable) in Rork iOS Apps
A field-tested checklist for diagnosing BGTaskScheduler.submit failing with Error Code=1 (Unavailable) in iOS apps built with Rork, walking through the six causes that account for nearly every case.
Dev Tools2026-06-14
When Your Rork App Gets ITMS-91053 — A Practical Guide to Privacy Manifests and Required Reason APIs
Submitting a Rork-generated Expo app to the App Store can trigger Privacy Manifest warnings even when you never wrote the offending code. Here is how to clear both Required Reason API and SDK manifest issues before you submit.
Dev Tools2026-06-12
Adding a Home Screen Widget to a Rork App — Making WidgetKit Work Within Expo's Constraints
Rork generates Expo apps, and home screen widgets can't be written in React Native. Here's how to wire up WidgetKit with a config plugin and App Groups — including the parts that tripped me up.
📚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 →