I’m using the react-native-background-actions library to run background tasks (location tracking) in my React Native app. I want to ensure that the background task stops when the app is killed (either by the user or the system). Here is my background action code
const locationTrackingTask = async (taskDataArguments) => {
const { delay } = taskDataArguments;
try {
const locationOptions = {
enableHighAccuracy: true,
distanceFilter: 0,
interval: 5000
};
const watcher = Geolocation.watchPosition(
async (position) => {
try {
// API call to send location to the server
const res = await createTraces(payload);
} catch (traceError) {
console.error("Error creating trace:", traceError);
}
},
(error) => {
console.error("Geolocation error:", error);
},
locationOptions
);
// Continuously check if the background service is running
while (BackgroundService.isRunning()) {
await sleep(delay);
}
Geolocation.clearWatch(watcher);
} catch (tripError) {
console.error("Error creating trip:", tripError);
}
};
const options = {
taskName: 'Location Tracking',
taskTitle: 'Ritis App Location Tracking Ongoing',
taskDesc: 'Location Tracking is in progress',
taskIcon: {
name: 'ic_launcher',
type: 'mipmap',
},
color: '#ff00ff',
linkingURI: 'yourSchemeHere://chat/jane', // See Deep Linking for more info
parameters: {
delay: 5000,
},
};
const startBackGroundTracking = async (id) => {
try {
await BackgroundService.start(locationTrackingTask, options);
if (BackgroundService.isRunning()) {
await BackgroundService.updateNotification({ taskDesc: 'Tracking in Progress' });
}
} catch (error) {
console.error('Error starting the background service:', error);
}
};
const stopBackGroundTracking = async () => {
try {
await BackgroundService.stop();
} catch (error) {
console.error('Error stopping the background service:', error);
}
};
I have added listeners for app state changes in index.js file of the library, to stop the background task when the app becomes inactive. However, this doesn’t seem to work when the app is killed. What is the correct way to handle this scenario in react-native-background-actions?
Any help or suggestions would be appreciated.
import { Platform, AppRegistry, AppState } from 'react-native';
import { RNBackgroundActions, nativeEventEmitter } from './RNBackgroundActionsModule';
import EventEmitter from 'eventemitter3';
class BackgroundServer extends EventEmitter {
constructor() {
super();
this._runnedTasks = 0;
this._stopTask = () => {};
this._isRunning = false;
this._currentOptions = null;
this._addListeners();
**this._handleAppStateChange = this._handleAppStateChange.bind(this); //added
AppState.addEventListener('change', this._handleAppStateChange); //added**
}
_addListeners() {
nativeEventEmitter.addListener('expiration', () => this.emit('expiration'));
}
**//added
_handleAppStateChange(nextAppState) {
if (nextAppState === 'inactive') {
this.stop();
}
}**
async updateNotification(taskData) {
if (Platform.OS !== 'android') return;
if (!this.isRunning())
throw new Error('A BackgroundAction must be running before updating the notification');
this._currentOptions = this._normalizeOptions({ ...this._currentOptions, ...taskData });
await RNBackgroundActions.updateNotification(this._currentOptions);
}
isRunning() {
return this._isRunning;
}
async start(task, options) {
this._runnedTasks++;
this._currentOptions = this._normalizeOptions(options);
const finalTask = this._generateTask(task, options.parameters);
if (Platform.OS === 'android') {
AppRegistry.registerHeadlessTask(this._currentOptions.taskName, () => finalTask);
await RNBackgroundActions.start(this._currentOptions);
this._isRunning = true;
} else {
await RNBackgroundActions.start(this._currentOptions);
this._isRunning = true;
finalTask();
}
}
_generateTask(task, parameters) {
const self = this;
return async () => {
await new Promise((resolve) => {
self._stopTask = resolve;
task(parameters).then(() => self.stop());
});
};
}
_normalizeOptions(options) {
return {
taskName: options.taskName + this._runnedTasks,
taskTitle: options.taskTitle,
taskDesc: options.taskDesc,
taskIcon: { ...options.taskIcon },
color: options.color || '#ffffff',
linkingURI: options.linkingURI,
progressBar: options.progressBar,
};
}
async stop() {
if (this._isRunning) {
this._stopTask();
await RNBackgroundActions.stop();
this._isRunning = false;
}
}
}
const backgroundServer = new BackgroundServer();
export default backgroundServer;
Jr Dev is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.