Implementing Background Tasks
1. Running Tasks in Background
Example: Using AsyncStorage for Background Data Persistence
import AsyncStorage from '@react-native-async-storage/async-storage';
const storeData = async (key, value) => {
try {
await AsyncStorage.setItem(key, JSON.stringify(value));
} catch (error) {
console.error('Error storing data:', error);
}
};
const getData = async (key) => {
try {
const value = await AsyncStorage.getItem(key);
return value ? JSON.parse(value) : null;
} catch (error) {
console.error('Error retrieving data:', error);
return null;
}
};
// Example usage
storeData('userPreferences', { theme: 'dark', notifications: true });
| Task Type | Description | Platform Support | Notes |
|---|---|---|---|
| Background Fetch | Periodically fetch data in the background | iOS, Android | Use BackgroundFetch module for periodic updates |
| Headless JS | Execute JavaScript without UI | Android | Allows running JS code when app is not in foreground |
| Push Notifications | Trigger background tasks via push | iOS, Android | Use Firebase Cloud Messaging or similar services |
| WorkManager (Android) | Run tasks on Android with WorkManager | Android | Part of AndroidX library, handles lifecycle management |
Note: Background execution limits vary by platform and OS version. Always test on target devices.
Warning: Excessive background activity can lead to app rejection from app stores.
2. Using Background Fetch
| Property | Description | Default | Notes |
|---|---|---|---|
| backgroundFetch | Enables background fetch capability | false | Requires configuration in Info.plist (iOS) or AndroidManifest.xml (Android) |
| minimumFetchInterval | Minimum time (in seconds) between fetch operations | 300 | Minimum is 300 seconds (5 minutes) |
| stopOnTerminate | Whether to stop background fetch when app is terminated | true | Set to false to continue fetching in background |
Example: Configure Background Fetch
import BackgroundFetch from 'react-native-background-fetch';
BackgroundFetch.configure({
minimumFetchInterval: 15, // Fetch every 15 seconds
stopOnTerminate: false,
}, (taskId) => {
console.log('[BackgroundFetch] Fetch task: ' + taskId);
// Perform data sync or other background work
BackgroundFetch.finish(taskId);
});
Note: On iOS, background fetch requires the
UIBackgroundModes key in Info.plist with value fetch.
Warning: Background fetch is not guaranteed to run at the specified interval. The OS may adjust based on battery life and network conditions.
3. Implementing Background Geolocation
| Property | Description | Default | Notes |
|---|---|---|---|
| enableHighAccuracy | Enables high accuracy mode for location | true |
May impact battery life |
| distanceFilter | Minimum distance (meters) to travel before updating location | 10 |
Set to 0 for updates on every move |
| interval | How often to fetch location (ms) | 10000 |
Minimum 5000ms for battery efficiency |
| fastestInterval | Fastest interval to fetch location (ms) | 5000 |
Must be less than or equal to interval |
| stationaryRadius | Distance (meters) to consider device as stationary | 20 |
Used to stop frequent updates when idle |
| stopOnTerminate | Stop background task when app is terminated | false |
Set to true if you want it to stop |
| startOnBoot | Start background task on device boot | false |
Requires ACCESS_FINE_LOCATION permission |
Example: Configure Background Geolocation
import Geolocation from '@react-native-community/geolocation';
Geolocation.configure({
enableHighAccuracy: true,
distanceFilter: 10,
interval: 10000,
fastestInterval: 5000,
stationaryRadius: 20,
stopOnTerminate: false,
startOnBoot: true
});
Geolocation.startBackgroundTask();
Example: Handle Location Updates
Geolocation.watchPosition(
(location) => {
console.log('Location:', location.coords);
},
(error) => {
console.log('Error:', error);
},
{
enableHighAccuracy: true,
distanceFilter: 10
}
);
Note: On Android, you must request
ACCESS_FINE_LOCATION and ACCESS_BACKGROUND_LOCATION permissions for background geolocation to work.
Warning: Background location tracking can drain battery quickly. Always set
distanceFilter and interval to reasonable values.
4. Scheduling Background Jobs
| Property | Description | Values |
|---|---|---|
| jobId | Unique identifier for the background job | string |
| interval | Time interval in milliseconds to repeat the job | number |
| data | Arbitrary data to pass to the job function | object |
| repeat | Whether to repeat the job | true or false |
Example: Scheduling a Background Job
import BackgroundFetch from 'react-native-background-fetch';
const jobConfig = {
jobId: 'my-background-job',
interval: 300000, // 5 minutes
data: { message: 'Hello from background' },
repeat: true
};
BackgroundFetch.scheduleJob(jobConfig);
Note: Ensure that the background fetch permission is granted by the user for jobs to run.
Warning: Background jobs may be throttled or paused by the OS to preserve battery life.
5. Handling Background Notifications
| Property | Description | Values |
|---|---|---|
| notification | Notification object received in background | { title: string, body: string, data?: object } |
| action | Action taken by user | 'received' | 'dismissed' | 'pressed' |
Example: Handling Background Notification
import { Notifications } from 'expo-notifications';
Notifications.setNotificationHandler({
handleNotification: async (notification) => {
return {
shouldShowAlert: true,
shouldPlaySound: true,
shouldSetBadge: false
};
}
});
// Listen for notifications while app is in background
Notifications.addNotificationReceivedListener((notification) => {
console.log('Background notification received:', notification);
});
Notifications.addNotificationResponseReceivedListener((response) => {
console.log('User pressed notification:', response);
});
Note: Background notifications require proper permissions and configuration in
app.json.
Key Points
- Use
Notifications.addNotificationReceivedListenerto handle notifications when app is in background - Use
Notifications.addNotificationResponseReceivedListenerto handle user interaction with notifications - Configure notification permissions in
app.jsonfor iOS and Android
6. Using Headless JS
Headless JS allows you to run JavaScript code in the background, even when the app is not in the foreground. It's particularly useful for tasks like syncing data, processing notifications, or performing long-running operations.
| Feature | Description | Notes |
|---|---|---|
| Headless JS | Enables background execution of JavaScript code in React Native apps. | Available on both iOS and Android platforms. |
| Task Registration | Register tasks using AppRegistry.registerHeadlessTask. |
Must be registered before the app starts. |
| Task Execution | Tasks are executed in a separate JavaScript context. | Does not block the main UI thread. |
Example: Registering a Headless JS Task
import { AppRegistry } from 'react-native';
const backgroundTask = async (taskData) => {
// Perform background work here
console.log('Background task executed:', taskData);
};
AppRegistry.registerHeadlessTask('MyBackgroundTask', () => backgroundTask);
Example: Triggering a Headless JS Task
import { NativeModules } from 'react-native';
const triggerBackgroundTask = () => {
NativeModules.BackgroundTask.runBackgroundTask({
taskName: 'MyBackgroundTask',
data: { message: 'Hello from background!' }
});
};
triggerBackgroundTask();
Note: On Android, Headless JS tasks are not supported in all versions of React Native. Ensure compatibility with your target version.
Warning: Background tasks may be limited by platform restrictions and battery optimization settings.
7. Implementing Background Audio
| Property | Description | Notes |
|---|---|---|
| backgroundAudio | Enables audio playback in the background | Requires proper permissions and configuration |
| audioCategory | Defines the audio category for playback | Options: playback, ambient, soloAmbient |
| audioMode | Configures audio mode for iOS | Options: default, ambient, playAndRecord |
Example: Setting up Background Audio
import { Audio } from 'expo-av';<br><br>Audio.setAudioModeAsync({<br> androidMode: 'playback',<br> iosCategory: 'playback',<br> staysActiveInBackground: true,<br>});
Note: On iOS, ensure
AVAudioSession is configured correctly to allow background audio.
Warning: Background audio may drain battery quickly. Implement proper cleanup to avoid memory leaks.
| Platform | Support Status | Notes |
|---|---|---|
Android |
Supported | Requires FOREGROUND_SERVICE permission |
iOS |
Supported | Uses AVAudioSession |
Web |
Limited | Background audio not supported natively |
8. Managing Battery Optimization
| Property | Description | Values | Notes |
|---|---|---|---|
| backgroundTaskId | Identifier for the registered background task | string |
Used to manage and cancel tasks |
| taskName | Name of the background task | string |
Used for logging and debugging |
Example: Registering a Background Task
import { AppState } from 'react-native';\n\nconst backgroundTaskId = await BackgroundFetch.scheduleTask({\n taskId: 'com.example.background-task',\n delay: 30000,\n periodic: true,\n});
Note: Battery optimization is critical for mobile apps. Use background tasks sparingly to avoid draining the battery.
Warning: Some devices may restrict background execution. Always test on real devices.
| Platform | Support | Notes |
|---|---|---|
| Android | Good | Uses WorkManager for task scheduling |
| iOS | Good | Uses Background App Refresh |
9. Testing Background Tasks
Example: Testing Background Task with Jest
import { NativeModules } from 'react-native';
import { jest, it, expect } from '@jest/globals';
// Mock the native module
NativeModules.BackgroundTaskManager = {
startBackgroundTask: jest.fn(),
stopBackgroundTask: jest.fn(),
};
it('should start and stop background task', () => {
const taskId = NativeModules.BackgroundTaskManager.startBackgroundTask();
expect(taskId).toBe(123);
NativeModules.BackgroundTaskManager.stopBackgroundTask(taskId);
});
| Method | Description | Return Type | Notes |
|---|---|---|---|
| startBackgroundTask | Starts a new background task | number |
Unique task ID |
| stopBackgroundTask | Stops a background task by ID | void |
Task must be running |
Note: Background tasks are limited by platform-specific constraints and may not run indefinitely.
Warning: Testing background tasks requires platform-specific mocking or real device testing.
Testing Considerations
- Use
NativeModulesto mock native implementations - Test task lifecycle (start, stop)
- Validate task IDs and return values
- Ensure proper cleanup after tests
10. Handling Background Limitations
Note: React Native's background task capabilities are limited compared to native mobile development. These limitations are primarily due to platform restrictions and battery optimization measures in iOS and Android.
| Task Type | Platform Support | Limitations | Notes |
|---|---|---|---|
| Background Fetch | iOS / Android | Maximum 15 minutes interval, limited to 30 seconds of execution time | Available via BackgroundFetch library on both platforms |
| Headless JS | Android / iOS | Only runs when app is in background or terminated, limited to 10 seconds | Useful for processing data without UI interaction |
| Push Notifications | iOS / Android | Requires permission, limited payload size (2KB on iOS) | Can trigger background tasks via PushNotificationIOS |
| Location Updates | iOS / Android | Background location updates are restricted to specific accuracy levels | Use react-native-geolocation-service for enhanced control |
| Audio Playback | iOS / Android | Audio must be played through system audio session (e.g., AVAudioSession) | Use react-native-sound or expo-av for playback |
Example: Background Fetch Configuration
import BackgroundFetch from 'react-native-background-fetch';
BackgroundFetch.configure({
stopOnTerminate: false,
startOnBoot: true,
enableHeadless: true,
}, async (taskId) => {
console.log('[js] Received background-fetch event:', taskId);
// Perform data sync or other operations here
await fetch('https://api.example.com/data');
BackgroundFetch.finish(taskId);
});
Example: Push Notification Setup
import PushNotificationIOS from '@react-native-push-notification/ios';
PushNotificationIOS.addEventListener('notification', (notification) => {
// Handle notification in background
const data = notification.getData();
console.log('Received push notification:', data);
});