Flutter后台定位插件carp_background_location的使用

发布于 1周前 作者 h691938207 来自 Flutter

Flutter后台定位插件carp_background_location的使用

CARP Background Location Plugin 是一个用于Android和iOS平台的后台定位插件,它可以在应用程序处于后台时继续工作。这个插件是background_locator_2的一个简单包装器。关于安装和设置的指导,请参考background_locator_2wiki页面

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标签内添加如下内容:

<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"/>

注意: 在Android 11及以上版本中,位置权限不能通过manifest文件自动设置。您需要引导用户手动将权限设置为“允许所有时间”。

iOS设置

修改Info.plist

Info.plist中添加以下键值对:

<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>This app needs access to location when open and in the background.</string>
<key>NSLocationAlwaysUsageDescription</key>
<string>This app needs access to location when in the background.</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>This app needs access to location when open.</string>
<key>UIBackgroundModes</key>
<array>
    <string>location</string>
</array>

修改AppDelegate.swift

覆盖您的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)
  }
}

使用方法

以下是使用carp_background_location的基本示例代码:

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

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

class MyApp extends StatefulWidget {
  @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
  void initState() {
    super.initState();

    // 配置位置管理器
    LocationManager().interval = 1;
    LocationManager().distanceFilter = 0;
    LocationManager().notificationTitle = 'CARP Location Example';
    LocationManager().notificationMsg = 'CARP is tracking your location';

    _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("No location yet");
    else
      return Column(
        children: <Widget>[
          Text(
            '${_lastLocation!.latitude}, ${_lastLocation!.longitude}',
          ),
          Text(
            '@',
          ),
          Text(
              '${DateTime.fromMillisecondsSinceEpoch(_lastLocation!.time ~/ 1)}')
        ],
      );
  }

  @override
  void dispose() => super.dispose();

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('CARP Background Location'),
        ),
        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(),
              ],
            ),
          ),
        ),
      ),
    );
  }
}

功能与问题

如果您有任何功能请求或遇到bug,请在issue tracker上提交。

许可证

该软件由Copenhagen Center for Health Technology (CACHET)持有版权,并遵循MIT许可证发布。更多信息请参见许可证


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

1 回复

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


当然,下面是一个关于如何在Flutter项目中使用carp_background_location插件来实现后台定位的示例代码。这个插件允许应用在后台持续获取用户的位置信息。

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

dependencies:
  flutter:
    sdk: flutter
  carp_background_location: ^x.y.z  # 请替换为最新版本号

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

接下来,你需要在Android和iOS项目中配置一些必要的权限和设置。

Android配置

android/app/src/main/AndroidManifest.xml文件中添加以下权限:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.yourapp">

    <!-- 其他配置 -->

    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />

    <!-- 其他配置 -->

</manifest>

android/app/build.gradle文件中确保你的minSdkVersion至少为23(Android 6.0 Marshmallow),因为后台定位需要这个API级别或更高:

android {
    compileSdkVersion 30

    defaultConfig {
        applicationId "com.example.yourapp"
        minSdkVersion 23
        targetSdkVersion 30
        versionCode 1
        versionName "1.0"
    }

    // 其他配置
}

iOS配置

ios/Runner/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>

Flutter代码实现

在你的Flutter项目中,你需要初始化carp_background_location插件并设置后台定位监听器。以下是一个简单的示例:

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

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

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  late DataCollectionService _dataCollectionService;
  late DataCollectionClientConfig _config;

  @override
  void initState() {
    super.initState();
    // 初始化配置
    _config = DataCollectionClientConfig(
      deviceRole: DeviceRole.PHONE,
      studyId: 'your_study_id',
      participantId: 'your_participant_id',
    );

    // 初始化数据收集服务
    _dataCollectionService = DataCollectionService(
      config: _config,
      sampleRate: Duration(seconds: 5),  // 每5秒收集一次位置数据
      onSample: (sample) {
        if (sample is LocationDataPoint) {
          // 处理位置数据
          print('Latitude: ${sample.latitude}, Longitude: ${sample.longitude}');
        }
      },
    );

    // 请求权限并开始收集数据
    _requestPermissionsAndStart();
  }

  Future<void> _requestPermissionsAndStart() async {
    // 请求位置权限
    bool hasPermission = await _dataCollectionService.requestLocationPermissions();
    if (hasPermission) {
      // 开始收集位置数据
      await _dataCollectionService.start();
    } else {
      // 处理权限被拒绝的情况
      print('位置权限被拒绝');
    }
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('后台定位示例'),
        ),
        body: Center(
          child: Text('检查控制台以查看位置数据'),
        ),
      ),
    );
  }

  @override
  void dispose() {
    // 停止数据收集服务
    _dataCollectionService.stop();
    super.dispose();
  }
}

这个示例展示了如何初始化carp_background_location插件,请求位置权限,并开始定期收集位置数据。收集到的位置数据会在控制台中打印出来。

请注意,实际应用中你可能需要更复杂的错误处理和权限管理逻辑,以及考虑数据隐私和安全性问题。此外,后台定位可能会消耗更多的电池电量,因此请确保你的应用有足够的理由在后台运行并收集位置数据。

回到顶部