Skip to content

Android Headless Mode

Chris Scott edited this page Dec 20, 2024 · 7 revisions

BackgroundGeolocation implements the React Native Headless JS mechanism. With Headless JS, you can continue to respond to BackgroundGeolocation events after your app has been terminated (assuming you've configured stopOnTerminate: false).

Tip

For more information, see the API docs:

Step 1: enableHeadless: true.

Where you execute BackgroundGeolocation.ready(config), add the following options:

export default class App extends Component {
  componentDidMount() {
    
    BackgroundGeolocation.ready({
      enableHeadless: true,
      stopOnTerminate: false,  // <-- required for Headless JS
      .
      .
      .
    }, (state) => {
      console.log('- Configure success');
    });

Step 2: BackgroundGeolocation.registerHeadlessTask(task)

In your application's index.js file, register your Javascript Headless Task:

Warning

index.js is the ONLY place where you can register your headless-task.

πŸ“‚ index.js

import { AppRegistry } from 'react-native';
import App from './src/App';

AppRegistry.registerComponent('MyApp', () => App);

////
// Define your Headless task -- simply a javascript async function to receive 
// events from BackgroundGeolocation:
//
const BGHeadlessTask = async (event) => {
  const params = event.params;
  console.log('[BackgroundGeolocation HeadlessTask] -', event.name, params);
  
  switch (event.name) {
    case 'terminate':
      await doCustomWork();
      break;
    case 'heartbeat':
      // Use await for async tasks
      const location = await getCurrentPosition({
        samples: 1,
        extras: {
          headless: true
        },
        persist: true
      });
      console.log('[BackgroundGeolocation HeadlessTask] - getCurrentPosition:', location);
      break;
  }  
}

////
// You're free to execute any kind of work within your headless-task (eg: HTTP requests), just be sure to wrap in a Promise
// and await the result (
//
const doCustomWork = () => {
  return new Promise((resolve) => {     
    // Simulate a long-running task, such as an HTTP request.
    console.log('[doWork] START');
    setTimeout(() => {
      console.log('[doWork] FINISH');
      resolve();
    }, 10000);
  });
};

////
// Register your HeadlessTask with BackgroundGeolocation plugin.
//
BackgroundGeolocation.registerHeadlessTask(BGHeadlessTask);

Testing

To test HeadlessJS, boot your app and connect the developer console. Terminate your app and observe console messages arriving from your registered HeadlessTask:

In $ adb logcat, you'll see HeadlessTask events prefixed with the "πŸ’€" icon (as in dead / terminated). These "πŸ’€" events are logged just before being sent to your HeadlessTask:

$ adb logcat -s TSLocationManager

TSLocationManager: [c.t.r.HeadlessTask <init>] πŸ’€  event: terminate
TSLocationManager: [c.t.l.a.BackgroundGeolocation isMainActivityActive] NO
TSLocationManager: [c.t.r.HeadlessTask onHeadlessJsTaskStart] taskId: 1
TSLocationManager: [c.t.l.BackgroundGeolocationService onActivityRecognitionResult] 
TSLocationManager: [c.t.r.HeadlessTask <init>] πŸ’€  event: activitychange
TSLocationManager: [c.t.l.a.BackgroundGeolocation isMainActivityActive] NO
TSLocationManager: [c.t.r.HeadlessTask onHeadlessJsTaskFinish] taskId: 1
TSLocationManager: [c.t.l.a.BackgroundGeolocation isMainActivityActive] NO
TSLocationManager: [c.t.l.BackgroundGeolocationService onActivityRecognitionResult] 
TSLocationManager: [c.t.r.HeadlessTask <init>] πŸ’€  event: activitychange
TSLocationManager: [c.t.r.HeadlessTask onHeadlessJsTaskStart] taskId: 3
TSLocationManager: [c.t.l.a.BackgroundGeolocation isMainActivityActive] NO
TSLocationManager: [c.t.r.HeadlessTask onHeadlessJsTaskFinish] taskId: 3
TSLocationManager: [c.t.l.LocationService onHeartbeat] ❀️
TSLocationManager: [c.t.l.a.BackgroundGeolocation isMainActivityActive] NO
TSLocationManager: [c.t.r.HeadlessTask <init>] πŸ’€  event: heartbeat