Implementing Background Fetch for Data Refresh
User opens app and sees current data—without waiting for load. Result of proper background sync. Done improperly—drained battery and user complaints.
iOS: BGAppRefreshTask
Since iOS 13, Apple moved background updates to BackgroundTasks framework. Old UIApplication.setMinimumBackgroundFetchInterval works but deprecated.
Task registration:
BGTaskScheduler.shared.register(
forTaskWithIdentifier: "com.myapp.refresh",
using: nil
) { task in
self.handleAppRefresh(task: task as! BGAppRefreshTask)
}
Identifier must be in Info.plist under BGTaskSchedulerPermittedIdentifiers. Without this task won't register—no errors, just nothing happens. Typical first-time mistake.
Next run scheduled at end of current via BGAppRefreshTaskRequest. Minimum interval set via earliestBeginDate, but iOS decides actual run—considering battery, usage patterns, charge. No guarantees on specific time.
Important: background task has CPU time limit. If task doesn't finish in time, system calls task.expirationHandler. Must save progress and call task.setTaskCompleted(success: false).
Android: WorkManager
WorkManager—right tool for periodic tasks on Android. Replaces JobScheduler, AlarmManager, SyncAdapter in most cases.
val refreshRequest = PeriodicWorkRequestBuilder<DataRefreshWorker>(
repeatInterval = 1,
repeatIntervalTimeUnit = TimeUnit.HOURS,
flexTimeInterval = 15,
flexTimeIntervalUnit = TimeUnit.MINUTES
)
.setConstraints(
Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)
.setRequiresBatteryNotLow(true)
.build()
)
.build()
WorkManager.getInstance(context).enqueueUniquePeriodicWork(
"data_refresh",
ExistingPeriodicWorkPolicy.KEEP,
refreshRequest
)
ExistingPeriodicWorkPolicy.KEEP—doesn't overwrite existing task on enqueue rerun. Important on each app launch.
Minimum interval for PeriodicWorkRequest—15 minutes. System won't allow less.
What to Do in Background Task
Background task should be minimal: request only changed (incremental sync), save to local database (Room / Core Data), send local notification if important changes.
Don't do in background: heavy computation, large HTTP requests without timeout, sync work with UI layer.
React Native and Flutter
In React Native, background tasks via native modules. Library react-native-background-fetch wraps BGAppRefreshTask on iOS and JobScheduler/WorkManager on Android in single JS API.
In Flutter—workmanager plugin for Android, background_fetch for iOS. Same limitations as native platforms—abstraction doesn't remove platform constraints.
Timeline: single platform—3-5 days, iOS + Android with edge case testing (battery, no network, Doze Mode)—1-1.5 weeks.







