如何使用Flutter在后台跟踪位置?

7

我一直在与一个使用Flutter开发应用的团队合作。我们需要使用GPS追踪行驶距离,但挑战在于Flutter不再允许前景和后台位置跟踪(即使使用粗略的精度级别)。

根据最新的Google指南审查,看起来Google应该允许我们的应用在后台跟踪设备,但事实并非如此。事实上,启用前景和后台位置服务似乎在一个月或两个月前仍然有效。我们已经尝试了locationgeolocation包,但没有成功。任何一个在应用处于后台时都会立即停止跟踪,并且当应用回到前台时我们只得到一个位置大的跳变。

以下是我们尝试过的方法

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

应用程序代码使用地理位置
...
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.');
}
...
使用位置的应用代码
_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");
}

任何有关如何实现这一目标的指导都将不胜感激。
6个回答

3
尝试使用flutter_background_service。
flutter_background_service: ^2.4.6

所需设置:

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

在此后台服务中使用 geoloactor

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

}

这将发送一个通知并在单独的隔离区内运行你代码中 onStart 的部分。隔离区内的代码会一直运行(即使应用已从最近列表中清除)直到你停止后台服务。

对我来说,在iOS设备锁定后,它停止获取位置。有任何想法是什么出了问题? - Saad Bashir
可能是由于iOS对后台服务的限制。 - Thread_ripper

2
定位插件完美地工作并且免费使用。可能有几个原因导致它不能正常工作,比如其他外部应用在后台杀死了您的应用程序,或者您设备的默认操作系统在一段时间后停止了应用程序。
在您的Stateful WidgetinitState中调用服务启用代码。
您可以监听背景更改,如下所示:
location.onLocationChanged.listen((LocationData currentLocation) {
  // do whatever you want with new location
});

1
@egorikem 它回答了确切的问题,即如何在后台中获取Flutter的位置。 - MohitC
引用文档中的内容:“只有在应用程序未被终止的情况下才能正常工作。” - Paul

2

原生的Flutter仍不支持后台本地化。

我见过一些针对Android特定的表格,但都没有效果。

但是积极寻找后,我发现了这个库:

https://pub.dev/packages/flutter_background_geolocation

这是一款付费库,适用于生产环境(仅针对安卓密钥,iOS免费)。它运行得非常完美。
尽管有一定的成本(独特的终身成本),但性价比非常高。
强烈推荐使用。
注意:他们的文档和支持非常出色。

2

1

目前,我正在使用background_fetch,因为并非每个人都负担得起flutter_background_geolocation的价格,顺便提一下,这个插件也是来自同一家公司。

background_fetch: ^0.7.2 

目前在Android上运行良好,但在ios上需要一些时间,原因是苹果的后台处理算法,一旦使用,它将在苹果设备上也能正常工作。

这是链接-: https://pub.dev/packages/background_fetch

设置

   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');

嘿,这个解决方案只在应用程序在后台打开时才有效,对吧? - Francesco Vezzani
1
嘿@FrancescoVezzani,它可以在后台运行,即使应用程序已关闭。 - Jigar Fumakiya
1
同时,当应用程序在iOS和Android上被终止时,"killed"函数是否有效?因为文档中说:“当您的应用程序被终止时,iOS不再触发事件 - 对于iOS来说,不存在stopOnTerminate: false这样的东西。” 这对我来说并不清楚。 - Francesco Vezzani

1
这里有一个解决方法
使用flutter_foreground_task插件来保持你的任务在后台运行。这里的后台指的是当你的应用程序没有从最近的任务中关闭时。
使用fl_location插件来连续获取用户的位置变化。
请确保遵循README中提到的两个包的先决条件,以使你的应用程序在后台完全功能。
在实现flutter_foreground_task插件的接口时,请确保在TaskHandler的onStart()函数中监听FlLocation.getLocationStream()函数。
在监听FlLocation.getLocationStream()时,使用sendPort.send()函数将位置数据发送到主隔离区。
记得在主隔离区(你的应用程序运行的地方)监听端口。
现在,当你在主隔离区收到数据后,你可以随心所欲地处理它...可以发送到某个Web套接字或其他地方...
它在我的iOS 17.1.1和Android 13上运行良好。如果对你有效,请告诉我!

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接