简体   繁体   中英

How to track location in background with Flutter?

I have been working on a team developing an app in Flutter. We need to track the distance travelled using the GPS but the challenge is that Flutter no longer allows both foreground and background location tracking (even with a coarse level of accuracy).

Based on a review of the latest Google guidelines, it seems like Google should allow our app to track the device when it's in the background, but it does not. In fact, turning on foreground and background location services seemed to be working a month or two back. We have tried both the location and geolocation packages, to no avail. Either of them immediately stops tracking when the app is in the background and we get one big jump in location when the app is returned to the foreground.

Here's what we've tried

AndroidManifest.xml
...
<uses-permission android:name="android.permission.ACCESS_COURSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION"/>
...

App Code Using Geolocation
...
serviceEnabled = await Geolocator.isLocationServiceEnabled();
if (!serviceEnabled) {
 return Future.error('Location services are disabled.');
}

permission = await Geolocator.checkPermission();
if (permission == LocationPermission.denied) {
 permission = await Geolocator.requestPermission();
 if (permission == LocationPermission.denied) {
   return Future.error('Location permissions are denied');
 }
}

//Permission returns denied Location 
//this is due to the background permission in the android manifest
//turn off background permission and the permission is allowed
if (permission == LocationPermission.deniedForever)
 return Future.error(
     'Location permissions are permanently denied, we cannot request permissions.');
}
...
App Code Using Location
_serviceEnabled = await location.serviceEnabled();
if (!_serviceEnabled) {
 _serviceEnabled = await location.requestService();
 if (!_serviceEnabled) {
   print('Service could not be enabled');
   return false;
 }

// This code throws and exception even if I respond to the 
// Google prompts and I select allow location service and all the time access 
try {
 await location.enableBackgroundMode(enable: true);
} catch(error) {
 print("Can't set background mode");
}

Any guidance for how to achieve this would be much appreciated.

Natively, Flutter still doesn't support background localization.

I've seen some android-specific forms, but nothing was effective.

But actively looking, I found this lib:

https://pub.dev/packages/flutter_background_geolocation

It's a paid lib, to be used in production (for android keys. iOS is free). And it works perfectly.

Despite having a cost (which is unique and for life) the cost benefit is very good.

Highly recommend.

Note: Their documentation and support is wonderful.

Currently, I am using the background_fetch because everyone can't afford flutter_background_geolocation pricing BTW this plugin is also from the same company

background_fetch: ^0.7.2 

So far it's working fine in Android will work nicely but in ios, it will take some time reason being Apple's background process algorithm once it will get used then It will be fine in apple as well.

Here is the link-: https://pub.dev/packages/background_fetch

Setup

   int status = await BackgroundFetch.configure(
    BackgroundFetchConfig(
        minimumFetchInterval: 30,
        stopOnTerminate: true,
        enableHeadless: false,
        startOnBoot: false,
        requiresBatteryNotLow: false,
        requiresCharging: false,
        requiresStorageNotLow: false,
        requiresDeviceIdle: false,
        requiredNetworkType: NetworkType.NONE),
        (taskId){
         // This is the fetch-event callback.
        },
    
       (taskId){
      // This task has exceeded its allowed running time.
      // You must stop what you're doing and immediately finish(taskId)
    });
    print('[BackgroundFetch] configure success: $status');

The location plugin works perfectly and is free to use. There could be several reasons that it did not work for you like some other external application killing your app in background or just your devices default OS could be stopping the application after a while in background.

Call the service enabling code in the initState of your Stateful Widget .

You can listen to the background changes as:

location.onLocationChanged.listen((LocationData currentLocation) {
  // do whatever you want with new location
});

You need this flutter_background_service package for this.

This package will help you to run the location service in a separate isolate.

Try using flutter_background_service

flutter_background_service: ^2.4.6

Required setup:

await service.configure(
androidConfiguration: AndroidConfiguration(
  onStart: onStart,
  isForegroundMode: true,
  notificationChannelId: 'my_foreground',
  initialNotificationTitle: 'AWESOME SERVICE',
  initialNotificationContent: 'Initializing',
  foregroundServiceNotificationId: 888,
),);

Use geoloactor within this background service,

@pragma('vm:entry-point')
void onStart(ServiceInstance service) async {
 
  // use geolocator to get location here

}

This will shoot a notification and runs your code inside onStart on a separate isolate. The code inside isolate runs (even when the app is cleared from the recent) till you stop the background service.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM