Skip to content

Background Location Updates

Guillaume Bernos edited this page Apr 21, 2019 · 4 revisions

:construction: Work in Progress :construction:

The FlutterLocation Plugin has experimental supports for Background Location. Expect bugs, maybe more in iOS since I don't have a real device to test on it. Any report to help the development of this feature is more than welcome.

A sample app to help you start is available.

Demo App

Principle

You can register your application to receive location updates even when the application was closed by the user. The location updates will be dispatched 3 to 4 times by hour, or more often if the user has open another app that is using the Location service.

Installation

The first things to do is to switch to the master channel of flutter, the iOS native view plugin is only available on this channel for now:

flutter channel master

Then add the plugin to your dependencies with a link to the background_location branch in you pubspec.yaml:

dependencies:
  location:
    git:
      url: git://github.com/Lyokone/flutterlocation.git
      ref: background_location

Add the AndroidX necessaries dependencies in gradle.properties:

android.enableJetifier=true
android.useAndroidX=true
org.gradle.jvmargs=-Xmx1536M

Your application should launch correctly with this setup. Let's now add background location capabilities !

Android

To add the headless capability on Android, you have to declare a separate Application.java that will extends Flutter application. In android/app/src/main/java/com/.../your_package/ create an Application.java next to MainActivity.java.

package com.company.yourpackage;

import com.lyokone.location.LocationPlugin;
import io.flutter.app.FlutterApplication;
import io.flutter.plugin.common.PluginRegistry;
import io.flutter.plugins.GeneratedPluginRegistrant;

public class Application  extends FlutterApplication implements PluginRegistry.PluginRegistrantCallback {
    @Override
    public void onCreate() {
        super.onCreate();
        LocationPlugin.setPluginRegistrant(this);
    }

    @Override
    public void registerWith(PluginRegistry registry) {
        GeneratedPluginRegistrant.registerWith(registry);
    }
}

Don't forget to change the first line to your package name ! You can find it in MainApplication.java.

You then have to register this new Application in the AndroidManifest.xml to use it and have headless capability. Change io.flutter.app.FlutterApplication to .Application.

...
    <application
        android:name=".Application"
        android:label="location_example"
...

And in the same AndroidManifest.xml you have to specify which Activity is responsible of handling background location updates, which is the one of the plugin. You have to add everything between the receiver tags.

...
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>

        <receiver android:name="com.lyokone.location.BackgroundLocationBroadcastReceiver"
            android:enabled="true" android:exported="true">
            <intent-filter>
                <action android:name="com.lyokone.location.BackgroundLocationBroadcastReceiver.ACTION_PROCESS_UPDATES" />
            </intent-filter>
        </receiver>
    </application>

...

Your Android application is now ready to receive background location updates ! Let's move to iOS.

iOS

While Flutter is merging the AndroidManifest.xml of the plugin with the one of your application, you need to manually add the permission for iOS in your ios/Runner/Info.plist:

<dict>
	<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
	<string>I need it in background because ...</string>
	<key>NSLocationWhenInUseUsageDescription</key>
	<string>I need it in front because</string>
...

Please note that you need both permission to be able to be allow for background location updates.

Then you need to register your Application for headless execution, modify your AppDelegate.m with #import <location/LocationPlugin.h>, registerPlugins function and [LocationPlugin setPluginRegistrantCallback:registerPlugins]; :

#include "AppDelegate.h"
#include "GeneratedPluginRegistrant.h"

#import <location/LocationPlugin.h>

@implementation AppDelegate

void registerPlugins(NSObject<FlutterPluginRegistry>* registry) {
  [GeneratedPluginRegistrant registerWithRegistry:registry];
}

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
  [GeneratedPluginRegistrant registerWithRegistry:self];
  [LocationPlugin setPluginRegistrantCallback:registerPlugins];

  // Override point for customization after application launch.
  return [super application:application didFinishLaunchingWithOptions:launchOptions];
}
@end

Your iOS installation is ready to receive background location updates!

Usage

Let's now see how you can use the plugin for background notification: You use registerBackgroundLocation to register a callback function that will receive a list of Location periodically:

static void backgroundCallback(List<LocationData> locations) {
    print('Location data received from background: $locations');
}

void _registerListener() async {
    bool _permission = await _locationService.requestPermission();
    print("Permission: $_permission");
    if (_permission) {
      bool statusBackgroundLocation = await _locationService.registerBackgroundLocation(backgroundCallback);
      print("statusBackgroundLocation: $statusBackgroundLocation");
    } else {
      print("Permission denied");
    }
    
  }

  void _removeListener() async {
    await _locationService.removeBackgroundLocation();
  }

Please note that you need to have the location permission checked in order to receive background location.

General note

Background location and more generally waking up an application in the background can cause battery drain. Please note that taking too long to handle the callback can cause your application to be waked up less frequently by the system.

Clone this wiki locally
You can’t perform that action at this time.