Flutter后台定位插件flutter_location_bg的使用

Flutter后台定位插件flutter_location_bg的使用

Android设置

在您的AndroidManifest.xml文件中添加以下权限:

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
    <uses-permission android:name="android.permission.WAKE_LOCK" />
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>

之后,在<application>标签内包含以下条目:

<application
       ...
        <!-- 配置background_locator_2 -->
        <receiver android:name="yukams.app.background_locator_2.BootBroadcastReceiver"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED"/>
            </intent-filter>
        </receiver>        
        <service android:name="yukams.app.background_locator_2.IsolateHolderService"
            android:permission="android.permission.FOREGROUND_SERVICE"
            android:exported="true"
            android:foregroundServiceType = "location"/>
    </application>

注意:在Android 11及更高版本上,应用程序无法通过清单文件自动设置位置权限。Google在其页面上提到:

在Android 11(API级别30)及以上版本上,系统对话框不包括始终允许选项。用户必须在设置页面上手动启用后台位置。

因此,为了使此插件(及其示例应用)正常工作,您需要进入此设置屏幕并手动将权限设置为“始终允许”。

iOS设置

在您的Info.plist文件中添加以下条目:

<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>此应用需要在打开和后台时访问位置。</string>
<key>NSLocationAlwaysUsageDescription</key>
<string>此应用需要在后台时访问位置。</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>此应用需要在打开时访问位置。</string>
<key>UIBackgroundModes</key>
<array>
 <string>location</string>
</array>

接下来,用以下内容覆盖您的AppDelegate.swift文件:

import UIKit
import Flutter
import background_locator_2

func registerPlugins(registry: FlutterPluginRegistry) -> () {
    if (!registry.hasPlugin("BackgroundLocatorPlugin")) {
        GeneratedPluginRegistrant.register(with: registry)
    } 
}

@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
  override func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
  ) -> Bool {
    GeneratedPluginRegistrant.register(with: self)
    BackgroundLocatorPlugin.setPluginRegistrantCallback(registerPlugins)
    return super.application(application, didFinishLaunchingWithOptions: launchOptions)
  }
}

功能

请在此处提交功能请求和错误报告。

开始使用

请参阅示例应用以获取完整的使用示例。

使用示例

// 配置定位管理器
LocationManager().interval = 1;
LocationManager().distanceFilter = 0;
LocationManager().notificationTitle = 'CARP Location Example';
LocationManager().notificationMsg = 'CARP正在跟踪您的位置';

// 获取当前定位
await LocationManager().getCurrentLocation();

// 开始监听定位更新
StreamSubscription<LocationDto> locationSubscription = LocationManager()
    .locationStream
    .listen((LocationDto loc) => print(loc));

// 取消监听并停止定位管理器
locationSubscription?.cancel();
LocationManager().stop();

请参阅示例应用以获取完整的使用示例。

示例代码

import 'dart:async';
import 'package:flutter/material.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:flutter_location_bg/flutter_location_bg.dart';

void main() => runApp(MyApp());

class MyApp extends StatefulWidget {
  [@override](/user/override)
  _MyAppState createState() => _MyAppState();
}

enum LocationStatus { UNKNOWN, INITIALIZED, RUNNING, STOPPED }

class _MyAppState extends State<MyApp> {
  String logStr = '';
  LocationDto? _lastLocation;
  StreamSubscription<LocationDto>? locationSubscription;
  LocationStatus _status = LocationStatus.UNKNOWN;

  [@override](/user/override)
  void initState() {
    super.initState();

    LocationManager().interval = 1;
    LocationManager().distanceFilter = 0;
    LocationManager().notificationTitle = 'CARP Location Example';
    LocationManager().notificationMsg = 'CARP正在跟踪您的位置';

    _status = LocationStatus.INITIALIZED;
  }

  void getCurrentLocation() async => onData(await LocationManager().getCurrentLocation());

  void onData(LocationDto location) {
    print('>> $location');
    setState(() {
      _lastLocation = location;
    });
  }

  /// 是否已授予“始终允许”位置权限?
  Future<bool> isLocationAlwaysGranted() async => await Permission.locationAlways.isGranted;

  /// 尝试从用户那里请求“始终允许”位置权限。
  /// 如果成功返回`true`,否则返回`false`。
  Future<bool> askForLocationAlwaysPermission() async {
    bool granted = await Permission.locationAlways.isGranted;

    if (!granted) {
      granted = await Permission.locationAlways.request() == PermissionStatus.granted;
    }

    return granted;
  }

  /// 开始监听定位事件。
  void start() async {
    // 如果未授予位置权限,则请求位置权限
    if (!await isLocationAlwaysGranted()) await askForLocationAlwaysPermission();

    locationSubscription?.cancel();
    locationSubscription = LocationManager().locationStream.listen(onData);
    await LocationManager().start();
    setState(() {
      _status = LocationStatus.RUNNING;
    });
  }

  void stop() {
    locationSubscription?.cancel();
    LocationManager().stop();
    setState(() {
      _status = LocationStatus.STOPPED;
    });
  }

  Widget stopButton() => SizedBox(
        width: double.maxFinite,
        child: ElevatedButton(
          child: const Text('STOP'),
          onPressed: stop,
        ),
      );

  Widget startButton() => SizedBox(
        width: double.maxFinite,
        child: ElevatedButton(
          child: const Text('START'),
          onPressed: start,
        ),
      );

  Widget statusText() => Text("Status: ${_status.toString().split('.').last}");

  Widget currentLocationButton() => SizedBox(
        width: double.maxFinite,
        child: ElevatedButton(
          child: const Text('CURRENT LOCATION'),
          onPressed: getCurrentLocation,
        ),
      );

  Widget locationWidget() {
    if (_lastLocation == null) return Text("无位置数据");
    else return Column(
      children: <Widget>[
        Text(
          '${_lastLocation!.latitude}, ${_lastLocation!.longitude}',
        ),
        Text(
          '@',
        ),
        Text('${DateTime.fromMillisecondsSinceEpoch(_lastLocation!.time ~/ 1)}')
      ],
    );
  }

  [@override](/user/override)
  void dispose() => super.dispose();

  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('CARP后台定位'),
        ),
        body: Container(
          width: double.maxFinite,
          padding: const EdgeInsets.all(22),
          child: SingleChildScrollView(
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.center,
              children: <Widget>[
                startButton(),
                stopButton(),
                currentLocationButton(),
                Divider(),
                statusText(),
                Divider(),
                locationWidget(),
              ],
            ),
          ),
        ),
      ),
    );
  }
}

更多关于Flutter后台定位插件flutter_location_bg的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter后台定位插件flutter_location_bg的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


flutter_location_bg 是一个用于在 Flutter 应用中实现后台定位的插件。它允许应用在后台持续获取设备的位置信息,即使应用不在前台运行。这对于需要持续跟踪用户位置的应用(如健身应用、打车应用等)非常有用。

1. 添加依赖

首先,你需要在 pubspec.yaml 文件中添加 flutter_location_bg 插件的依赖:

dependencies:
  flutter:
    sdk: flutter
  flutter_location_bg: ^1.0.0 # 请使用最新版本

然后运行 flutter pub get 来安装依赖。

2. 配置 Android

为了在 Android 上使用后台定位,你需要进行以下配置:

2.1. 添加权限

AndroidManifest.xml 文件中添加以下权限:

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

2.2. 配置后台服务

AndroidManifest.xml 中添加以下服务声明:

<service
    android:name="com.example.flutter_location_bg.LocationBackgroundService"
    android:enabled="true"
    android:exported="false" />

3. 配置 iOS

在 iOS 上,你需要在 Info.plist 文件中添加以下键值对以请求定位权限:

<key>NSLocationAlwaysUsageDescription</key>
<string>我们需要您的位置信息来提供更好的服务。</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>我们需要您的位置信息来提供更好的服务。</string>

4. 使用插件

以下是如何在 Flutter 应用中使用 flutter_location_bg 插件的基本示例:

import 'package:flutter/material.dart';
import 'package:flutter_location_bg/flutter_location_bg.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: LocationScreen(),
    );
  }
}

class LocationScreen extends StatefulWidget {
  @override
  _LocationScreenState createState() => _LocationScreenState();
}

class _LocationScreenState extends State<LocationScreen> {
  LocationData? _locationData;

  @override
  void initState() {
    super.initState();
    _startLocationService();
  }

  void _startLocationService() async {
    await FlutterLocationBg.startLocationService(
      interval: Duration(seconds: 10), // 定位间隔时间
      distanceFilter: 10, // 距离过滤,单位:米
      notificationTitle: "后台定位服务",
      notificationText: "正在获取位置信息",
      callback: (LocationData locationData) {
        setState(() {
          _locationData = locationData;
        });
      },
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('后台定位示例'),
      ),
      body: Center(
        child: _locationData == null
            ? Text('正在获取位置信息...')
            : Text('位置信息: ${_locationData!.latitude}, ${_locationData!.longitude}'),
      ),
    );
  }
}

5. 停止后台定位服务

当你不再需要后台定位时,可以调用 FlutterLocationBg.stopLocationService() 来停止服务:

void _stopLocationService() async {
  await FlutterLocationBg.stopLocationService();
}
回到顶部