Skip to content

Android Headless Mode

Chris Scott edited this page Oct 27, 2022 · 25 revisions

The BackgroundGeolocation SDK provides an Android Headless Mechanism, enabled with Config.enableHeadless: true. Doing so allows you to provide your own dart callback to receive events after your app has been terminated.


ℹ️ iOS has no concept of "Headless". When an iOS app is launched in the background, due to a geofence event for example, the entire app is launched in the background, just as if launched from the home-screen icon.


Step 1: registerHeadlessTask

Open your main.dart file. Create a global function to receive headless events:

⚠️ This step must occur within main.dart. Do not attempt to create the headless-task in your Application component.

📂 main.dart

import 'package:flutter_background_geolocation/flutter_background_geolocation.dart' as bg;

// Be sure to annotate your callback for Flutter >= 3.3.0
@pragma('vm:entry-point')
void headlessTask(bg.HeadlessEvent headlessEvent) async {
  print('[BackgroundGeolocation HeadlessTask]: $headlessEvent');
  // Implement a 'case' for only those events you're interested in.
  switch(headlessEvent.name) {
    case bg.Event.TERMINATE:
      bg.State state = headlessEvent.event;
      print('- State: $state');
      break;
    case bg.Event.HEARTBEAT:
      bg.HeartbeatEvent event = headlessEvent.event;
      print('- HeartbeatEvent: $event');
      break;
    case bg.Event.LOCATION:
      bg.Location location = headlessEvent.event;
      print('- Location: $location');
      break;
    case bg.Event.MOTIONCHANGE:
      bg.Location location = headlessEvent.event;
      print('- Location: $location');
      break;
    case bg.Event.GEOFENCE:
      bg.GeofenceEvent geofenceEvent = headlessEvent.event;
      print('- GeofenceEvent: $geofenceEvent');
      break;
    case bg.Event.GEOFENCESCHANGE:
      bg.GeofencesChangeEvent event = headlessEvent.event;
      print('- GeofencesChangeEvent: $event');
      break;
    case bg.Event.SCHEDULE:
      bg.State state = headlessEvent.event;
      print('- State: $state');
      break;
    case bg.Event.ACTIVITYCHANGE:
      bg.ActivityChangeEvent event = headlessEvent.event;
      print('ActivityChangeEvent: $event');
      break;
    case bg.Event.HTTP:
      bg.HttpEvent response = headlessEvent.event;
      print('HttpEvent: $response');
      break;
    case bg.Event.POWERSAVECHANGE:
      bool enabled = headlessEvent.event;
      print('ProviderChangeEvent: $enabled');
      break;
    case bg.Event.CONNECTIVITYCHANGE:
      bg.ConnectivityChangeEvent event = headlessEvent.event;
      print('ConnectivityChangeEvent: $event');
      break;
    case bg.Event.ENABLEDCHANGE:
      bool enabled = headlessEvent.event;
      print('EnabledChangeEvent: $enabled');
      break;
  }
}

void main() {
  runApp(HelloWorld());
  // Register your headlessTask:
  BackgroundGeolocation.registerHeadlessTask(headlessTask);
}

⚠️ Warning:

  • You cannot register more than one headless-task.
  • You cannot reference your UI within your headless-task. There is no UI.
  • Do not register an inline function to registerHeadlessTask — the Flutter framework will fail to reference it:
// NO!  This will not work.
BackgroundGeolocation.registerHeadlessTask((HeadlessEvent event) {
  print('$event');
});

// YES!
void myHeadlessTask(HeadlessEvent headlessEvent) async {
  print('$event');
}

Step 2: enableHeadless: true

In your Application component, where you execute BackgroundGeolocation.ready, add the option enableHeadless: true:

⚠️ Never attempt to registerHeadlessTask here in your Application components — it will never work.

import 'package:flutter_background_geolocation/flutter_background_geolocation.dart' as bg;

class HelloWorldPage extends StatefulWidget {
  HelloWorldPage({Key key}) : super(key: key);

  @override
  _HelloWorldPageState createState() => new _HelloWorldPageState();
}

class _HelloWorldPageState extends State<HelloWorldPage> {
 
  @override
  void initState() {
    super.initState();    
    _initPlatformState();
  }

  Future<Null> _initPlatformState() async {
    bg.BackgroundGeolocation.onLocation((Location location) {
      print('[onLocation] $location');
    });
    
    bg.BackgroundGeolocation.ready(bg.Config(
      enableHeadless: true,    
      stopOnTerminate: false,  
      startOnBoot: true
    ));
  }
}