agents-inc/skills/src/skills/mobile-background-tasks/SKILL.md
mobile-background-tasks
Background fetch, processing tasks, background location, headless JS, battery optimization - Expo and bare React Native
- Source repository stars
- 23
- Declared platforms
- 0
- Static risk flags
- 0
- Last source update
- 2026-08-09
- Source checked
- 2026-08-28
Decision brief
What it does: where it fits
Quick Guide: Background tasks in React Native are heavily constrained by OS power management. Use expo-background-task (Expo) or react-native-background-fetch (bare RN) for periodic fetch. Use expo-location for background location tracking. iOS gives 30s for refresh tasks (BGApp…
Not for
- Tasks that require unconfirmed production actions or broad system permissions.
- Environments where the pinned source and install steps cannot be inspected.
Compatibility matrix
Platform support, with evidence labels
| Platform | Status | Evidence | What to check |
|---|---|---|---|
| Codex | Not declared | No explicit evidence | Portability before use |
| Claude Code | Not declared | No explicit evidence | Portability before use |
| Cursor | Not declared | No explicit evidence | Portability before use |
| Gemini CLI | Not declared | No explicit evidence | Portability before use |
Installation
Inspect first. Install second.
The source command is displayed only when detected. A safe inspection prompt is always available so your agent can explain every action before execution.
npx skills add https://github.com/agents-inc/skills --skill "src/skills/mobile-background-tasks"Inspect the Agent Skill "mobile-background-tasks" from https://github.com/agents-inc/skills/blob/81d43a51211aca12c85dcc16085fa99014ec548e/src/skills/mobile-background-tasks/SKILL.md at commit 81d43a51211aca12c85dcc16085fa99014ec548e. List every install step, command, network request, credential, file read/write, external action, and rollback step. Explain whether it fits my task. Do not install or execute anything until I approve.
Workflow
What the source asks the agent to do
- 01
CRITICAL: Before Using This Skill
All code must follow project conventions in CLAUDE.md (kebab-case, named exports, import ordering, import type, named constants)
Syncing data periodically while the app is backgrounded (new messages, feeds, email)Tracking location in the background (fitness, delivery, navigation)Running periodic cleanup or maintenance tasks (cache purge, log upload) - 02
Philosophy
Background execution on mobile is a privilege, not a right. Both iOS and Android aggressively limit what apps can do in the background to preserve battery life and user experience. The OS decides when (and whether) your task runs -- you can only request execution and set minimum…
Minimize background work -- Sync only deltas, not full datasets. The less you do, the more reliably the OS will schedule you.Always signal completion -- Return a result code or call finish(). The OS tracks your task duration and penalizes apps that don't complete promptly.Define tasks globally -- Background tasks must be registered at the top-level scope because the app may launch directly into background mode with no UI. - 03
Core Patterns
The modern Expo approach using BGTaskScheduler (iOS) and WorkManager (Android). Replaces the older expo-background-fetch.
The modern Expo approach using BGTaskScheduler (iOS) and WorkManager (Android). Replaces the older expo-background-fetch.Why good: Task defined at top-level scope (runs even when app launches in background), returns explicit result code, handles errorsWhy bad: Task definition inside component lifecycle will not execute when the OS launches the app headlessly in the background - 04
Pattern 1: Expo Background Task (expo-background-task)
The modern Expo approach using BGTaskScheduler (iOS) and WorkManager (Android). Replaces the older expo-background-fetch.
The modern Expo approach using BGTaskScheduler (iOS) and WorkManager (Android). Replaces the older expo-background-fetch.Why good: Task defined at top-level scope (runs even when app launches in background), returns explicit result code, handles errorsWhy bad: Task definition inside component lifecycle will not execute when the OS launches the app headlessly in the background - 05
Pattern 2: Bare RN Background Fetch (react-native-background-fetch)
For bare React Native projects (non-Expo). Wraps BGAppRefreshTask (iOS) and WorkManager (Android).
For bare React Native projects (non-Expo). Wraps BGAppRefreshTask (iOS) and WorkManager (Android).Why good: Explicit timeout handler for graceful cleanup, finish(taskId) signals OS completion, Android-specific options for post-termination behaviorSee examples/core.md for scheduleTask one-shot/periodic tasks and Headless JS setup.
Permission review
Static risk signals and limitations
No configured static risk pattern was detected
This is not proof of safety. Runtime behavior, indirect dependencies, and hidden external systems are outside the static scan.
Evidence record
Why each signal appears
| Signal | Value | Evidence type | Meaning |
|---|---|---|---|
| Quality score | 92/100 | Computed | Documentation, specificity, maintenance, and trust rules |
| Repository stars | 23 | Source | Repository attention, not individual Skill quality |
| Compatibility | 0 platforms | Source | Declared in the catalog source record |
| Usage guide | automated source guide | Editorial | Generated or reviewed according to the visible evidence level |
Pinned source
Provenance and original SKILL.md
- Repository
- agents-inc/skills
- Skill path
- src/skills/mobile-background-tasks/SKILL.md
- Commit
- 81d43a51211aca12c85dcc16085fa99014ec548e
- License
- MIT
- Collected
- 2026-08-28
- Default branch
- main
View the original SKILL.md
React Native Background Tasks
Quick Guide: Background tasks in React Native are heavily constrained by OS power management. Use
expo-background-task(Expo) orreact-native-background-fetch(bare RN) for periodic fetch. Useexpo-locationfor background location tracking. iOS gives ~30s for refresh tasks (BGAppRefreshTask) and several minutes for processing tasks (BGProcessingTask). Android enforces 15-minute minimum intervals via WorkManager and restricts execution in Doze mode. Always callfinish()or return a result when done -- the OS will terminate tasks that exceed their time budget.
<critical_requirements>
CRITICAL: Before Using This Skill
All code must follow project conventions in CLAUDE.md (kebab-case, named exports, import ordering,
import type, named constants)
(You MUST define tasks in the top-level scope (global) -- tasks defined inside React components or lifecycle methods will NOT be registered when the app starts from the background)
(You MUST call finish(taskId) or return a BackgroundTaskResult when task execution completes -- failing to signal completion causes the OS to penalize or kill your app)
(You MUST request background permissions explicitly on both platforms -- iOS requires Info.plist UIBackgroundModes entries, Android requires manifest permissions)
(You MUST handle the OS killing your task at any time -- use expiration listeners on iOS and timeout callbacks on Android to clean up gracefully)
(You MUST keep background work minimal -- sync only changed data, avoid heavy computation, respect the ~30s iOS refresh limit)
</critical_requirements>
Auto-detection: expo-task-manager, expo-background-task, expo-background-fetch, expo-location background, react-native-background-fetch, BackgroundFetch, TaskManager, defineTask, registerTaskAsync, startLocationUpdatesAsync, Headless JS, registerHeadlessTask, BGTaskScheduler, WorkManager, background fetch, background processing, background location
When to use:
- Syncing data periodically while the app is backgrounded (new messages, feeds, email)
- Tracking location in the background (fitness, delivery, navigation)
- Running periodic cleanup or maintenance tasks (cache purge, log upload)
- Keeping local data fresh so the app opens with current content
- Processing uploads or downloads that continue after backgrounding
When NOT to use:
- Real-time updates that need sub-second latency (use push notifications + foreground handling)
- Continuous audio playback (use the audio background mode, not task scheduling)
- Tasks that must execute at an exact time (OS scheduling is advisory, not precise)
- Tasks requiring more than a few minutes of CPU (iOS will terminate them)
Key patterns covered:
- Expo background tasks:
expo-background-task(new) andexpo-background-fetch(legacy) - Bare RN background fetch:
react-native-background-fetchwith configure/scheduleTask - Background location tracking with
expo-locationand TaskManager - Android Headless JS for post-termination task execution
- iOS BGTaskScheduler constraints (refresh ~30s vs processing ~minutes)
- Android battery optimization: Doze mode, App Standby, WorkManager guarantees
- Task registration, unregistration, and lifecycle management
Detailed Resources:
- examples/core.md - Expo background task, bare RN background fetch, background location, headless JS
- reference.md - Decision frameworks, platform constraints, permission checklists
Philosophy
Background execution on mobile is a privilege, not a right. Both iOS and Android aggressively limit what apps can do in the background to preserve battery life and user experience. The OS decides when (and whether) your task runs -- you can only request execution and set minimum intervals.
Core principles:
- Minimize background work -- Sync only deltas, not full datasets. The less you do, the more reliably the OS will schedule you.
- Always signal completion -- Return a result code or call
finish(). The OS tracks your task duration and penalizes apps that don't complete promptly. - Define tasks globally -- Background tasks must be registered at the top-level scope because the app may launch directly into background mode with no UI.
- Plan for termination -- The OS can kill your task at any time. Use expiration/timeout handlers to save partial progress.
- Test on real devices -- iOS simulators do not run BGTaskScheduler tasks. Android emulators may not enforce Doze mode.
- Respect platform differences -- iOS kills all background tasks when the user force-quits. Android Headless JS can survive app termination with proper configuration.
The background execution spectrum:
Most reliable Least reliable
| |
Push notifications > Foreground services > Background tasks > Timers
(instant delivery) (visible to user) (OS-scheduled) (killed)
Background tasks sit in the middle -- more reliable than timers, but entirely at the OS's discretion. For critical work, combine with push notifications as a trigger.
Core Patterns
Pattern 1: Expo Background Task (expo-background-task)
The modern Expo approach using BGTaskScheduler (iOS) and WorkManager (Android). Replaces the older expo-background-fetch.
import * as TaskManager from "expo-task-manager";
import * as BackgroundTask from "expo-background-task";
const SYNC_TASK_NAME = "BACKGROUND_SYNC_TASK";
const TWELVE_HOURS_IN_MINUTES = 720;
// MUST be top-level -- not inside a component
TaskManager.defineTask(SYNC_TASK_NAME, async () => {
try {
const hasNewData = await fetchLatestUpdates();
return hasNewData
? BackgroundTask.BackgroundTaskResult.Success
: BackgroundTask.BackgroundTaskResult.Failed;
} catch {
return BackgroundTask.BackgroundTaskResult.Failed;
}
});
Why good: Task defined at top-level scope (runs even when app launches in background), returns explicit result code, handles errors
// BAD: Defining task inside a component
function App() {
useEffect(() => {
// This will NOT work when app starts from background
TaskManager.defineTask(SYNC_TASK_NAME, async () => {
/* ... */
});
}, []);
}
Why bad: Task definition inside component lifecycle will not execute when the OS launches the app headlessly in the background
See examples/core.md for complete registration/unregistration lifecycle.
Pattern 2: Bare RN Background Fetch (react-native-background-fetch)
For bare React Native projects (non-Expo). Wraps BGAppRefreshTask (iOS) and WorkManager (Android).
import BackgroundFetch from "react-native-background-fetch";
const MIN_FETCH_INTERVAL_MINUTES = 15;
// Configure in app initialization (e.g., App component mount)
const status = await BackgroundFetch.configure(
{
minimumFetchInterval: MIN_FETCH_INTERVAL_MINUTES,
stopOnTerminate: false, // Android: continue after app killed
startOnBoot: true, // Android: restart after device reboot
enableHeadless: true, // Android: enable Headless JS
requiredNetworkType: BackgroundFetch.NETWORK_TYPE_ANY,
},
async (taskId) => {
// Task triggered -- do your work
await syncData();
BackgroundFetch.finish(taskId); // MUST call when done
},
async (taskId) => {
// Timeout -- OS is about to kill the task, clean up immediately
BackgroundFetch.finish(taskId);
},
);
Why good: Explicit timeout handler for graceful cleanup, finish(taskId) signals OS completion, Android-specific options for post-termination behavior
See examples/core.md for scheduleTask one-shot/periodic tasks and Headless JS setup.
Pattern 3: Background Location Tracking
Continuous location updates while backgrounded. Uses expo-location with expo-task-manager. Requires explicit background permission grants ("Always Allow" on iOS).
import * as TaskManager from "expo-task-manager";
import * as Location from "expo-location";
const LOCATION_TASK_NAME = "BACKGROUND_LOCATION_TASK";
// Top-level task definition
TaskManager.defineTask(LOCATION_TASK_NAME, async ({ data, error }) => {
if (error) {
console.error("Location task error:", error.message);
return;
}
if (data) {
const { locations } = data as { locations: Location.LocationObject[] };
await saveLocationsToServer(locations);
}
});
Why good: Top-level definition, explicit error handling, typed location data extraction
See examples/core.md for permission flow, start/stop, and accuracy configuration.
Pattern 4: Android Headless JS
Android-only mechanism for running JavaScript after app termination. Requires native setup and registration in index.js.
// index.js -- register headless task alongside app
import { AppRegistry } from "react-native";
import { App } from "./App";
const APP_NAME = "MyApp";
const HEADLESS_TASK_NAME = "com.transistorsoft.fetch"; // Default ID from react-native-background-fetch
AppRegistry.registerComponent(APP_NAME, () => App);
// Headless task runs when app is terminated but task fires
AppRegistry.registerHeadlessTask(HEADLESS_TASK_NAME, () => async (taskData) => {
await performSync(taskData);
// Task completes when promise resolves
});
Why good: Registered at app entry point, async function allows proper cleanup, runs even after app termination on Android
Gotcha: Headless JS is Android-only. iOS has no equivalent -- once the user force-quits the app, no background tasks run until the user reopens it.
See examples/core.md for complete headless setup with enableHeadless configuration.
Pattern 5: Task Registration and Unregistration Lifecycle
Always check registration status before registering, and unregister when tasks are no longer needed.
async function ensureBackgroundSyncRegistered(): Promise<void> {
const isRegistered = await TaskManager.isTaskRegisteredAsync(SYNC_TASK_NAME);
if (isRegistered) return;
await BackgroundTask.registerTaskAsync(SYNC_TASK_NAME, {
minimumInterval: TWELVE_HOURS_IN_MINUTES,
});
}
async function disableBackgroundSync(): Promise<void> {
const isRegistered = await TaskManager.isTaskRegisteredAsync(SYNC_TASK_NAME);
if (!isRegistered) return;
await BackgroundTask.unregisterTaskAsync(SYNC_TASK_NAME);
}
Why good: Guards against double-registration, idempotent enable/disable, named constants for intervals
See examples/core.md for status checking and debugging patterns.
<decision_framework>
Decision Framework
Choosing a Background Task Approach
What kind of background work do you need?
|
+-> Periodic data sync (every 15min - 12hrs)?
| +-> Expo project? --> expo-background-task
| +-> Bare RN? --> react-native-background-fetch
|
+-> Continuous location tracking?
| +-> Expo? --> expo-location + startLocationUpdatesAsync
| +-> Bare RN? --> react-native-background-geolocation
|
+-> Complete a task started in foreground (iOS 26+)?
| +-> BGContinuedProcessingTask (new in iOS 26)
|
+-> Long-running processing (ML, export)?
| +-> Foreground service with notification (Android)
| +-> BGProcessingTask (iOS, requires charger + network)
|
+-> Must survive app termination (Android)?
| +-> Headless JS + enableHeadless: true + stopOnTerminate: false
|
+-> Must execute at exact time?
+-> Not possible with background tasks
+-> Use push notifications + server-side scheduling
expo-background-task vs expo-background-fetch
| Feature | expo-background-task | expo-background-fetch |
|---|---|---|
| Status | Active (recommended) | Deprecated |
| iOS API | BGTaskScheduler | Legacy Background Fetch |
| Android API | WorkManager | JobScheduler |
| Min interval | 15 minutes | ~10 minutes (advisory) |
| Network required | Yes (by default) | No |
| Reliability | Higher | Lower |
Platform Execution Limits
| Constraint | iOS | Android |
|---|---|---|
| Refresh task time | ~30 seconds | ~10 minutes |
| Processing task time | Several minutes (charger required) | ~10 minutes |
| Minimum interval | 15 minutes (system-managed) | 15 minutes (WorkManager-enforced) |
| After force-quit | No tasks run | Headless JS can run (with config) |
| After reboot | Tasks resume automatically | Requires startOnBoot: true |
| Simulator support | No (physical device only for BGTaskScheduler) | Partial (Doze may not be enforced) |
</decision_framework>
<red_flags>
RED FLAGS
High Priority Issues:
- Defining tasks inside React components or useEffect -- tasks MUST be at the top-level scope or they won't run when the app starts from background
- Not calling
finish(taskId)or returning a result -- the OS will penalize your app, reducing future scheduling frequency or killing the task - Expecting exact timing -- background task intervals are minimums, the OS may delay execution by hours or even days on iOS
- Using
setTimeout/setIntervalfor background work -- these are killed immediately when the app is backgrounded - Not requesting background permissions -- iOS requires Info.plist UIBackgroundModes, Android requires ACCESS_BACKGROUND_LOCATION and RECEIVE_BOOT_COMPLETED
Medium Priority Issues:
- Doing heavy computation in a background refresh task -- iOS gives ~30 seconds, not minutes
- Not handling the timeout/expiration callback -- if the OS decides to stop your task early, you must save progress and exit
- Assuming background location works with "When In Use" permission -- it requires "Always Allow" on iOS
- Testing only on simulators -- iOS simulators do not execute BGTaskScheduler tasks
- Not checking
getStatusAsync()before registering -- background tasks may be restricted by user settings or device state
Gotchas & Edge Cases:
- iOS force-quit kills ALL background tasks until user reopens the app -- there is no workaround
- Android vendor battery optimizations (Samsung, Xiaomi, Huawei) may kill background tasks beyond stock Android Doze restrictions -- see dontkillmyapp.com
expo-background-taskrequires network connectivity by default -- tasks won't run offline- iOS BGTaskScheduler uses machine learning to predict when to run your task -- it may take days to "settle in" for newly installed apps
- WorkManager enforces a hard 15-minute minimum interval -- you cannot schedule more frequently
- Headless JS is Android-only -- iOS has no equivalent post-termination execution
expo-background-fetchis deprecated in favor ofexpo-background-task-- migrate to the new API- Background tasks registered with expo-task-manager persist across app restarts -- always check
isTaskRegisteredAsyncbefore re-registering - Android 15/16 edge-to-edge changes do not affect background tasks, but foreground service notification requirements have tightened
- iOS 26 introduces BGContinuedProcessingTask for completing user-initiated work in the background -- a new option for tasks started in foreground
</red_flags>
<critical_reminders>
CRITICAL REMINDERS
All code must follow project conventions in CLAUDE.md
(You MUST define tasks in the top-level scope (global) -- tasks defined inside React components or lifecycle methods will NOT be registered when the app starts from the background)
(You MUST call finish(taskId) or return a BackgroundTaskResult when task execution completes -- failing to signal completion causes the OS to penalize or kill your app)
(You MUST request background permissions explicitly on both platforms -- iOS requires Info.plist UIBackgroundModes entries, Android requires manifest permissions)
(You MUST handle the OS killing your task at any time -- use expiration listeners on iOS and timeout callbacks on Android to clean up gracefully)
(You MUST keep background work minimal -- sync only changed data, avoid heavy computation, respect the ~30s iOS refresh limit)
Failure to follow these rules will result in tasks that never execute, apps penalized by the OS scheduler, or apps rejected from the App Store for excessive background resource usage.
</critical_reminders>
Frequently asked questions
What to verify before installation and use
What does the mobile-background-tasks source document cover?
Quick Guide: Background tasks in React Native are heavily constrained by OS power management. Use expo-background-task (Expo) or react-native-background-fetch (bare RN) for periodic fetch. Use expo-location for background location tracking. iOS gives 30s for refresh tasks (BGApp…
How do I install mobile-background-tasks?
The source record exposes this install command: npx skills add https://github.com/agents-inc/skills --skill "src/skills/mobile-background-tasks". Inspect the command and pinned source before running it.
Alternatives
Compare before choosing
event4u-app/agent-config
existing-ui-audit
Use BEFORE writing or editing any non-trivial UI — inventories components, design tokens, shadcn primitives, and reusable patterns into state.ui_audit. Hard gate for the ui directive set.
kensaurus/cursor-kenji
enhance-web-web3d
Add purposeful 3D/WebGL and scroll choreography to an existing site with Three.js/R3F, GSAP, or Motion. Use when "add 3D", "WebGL hero", "React Three Fiber", or "scroll-driven 3D". General UI polish → enhance-web-ui. Motion without 3D → enhance-motion.
UiPath/skills
uipath-coded-apps
UiPath Coded Apps — scaffold, build, run, and deploy Coded Web Apps and Coded Action Apps: React/TypeScript apps that call UiPath Cloud APIs via the `@uipath/uipath-typescript` SDK and ship to Automation Cloud (push/pull to Studio Web, pack, publish, deploy, OAuth-PKCE). Also generates live analytics & governance dashboards from a plain-language request, wired to tenant data via the Insights real-time API, with edit and deploy flows. For RPA→uipath-rpa, Python agents→uipath-agents, Maestro flows
hyperfx-ai/marketing-skills
slack
Slack messaging, file sharing, Block Kit formatting, and channel management. Use when the user wants to send Slack messages, post rich Block Kit layouts, share files, react, or manage channels and members.