Flutter地理围栏服务插件geofence_service_in_app的使用

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

Flutter地理围栏服务插件geofence_service_in_app的使用

该插件是一个带有活动识别API的地理围栏服务。它不使用平台实现的地理围栏API,因此无法保证电池效率。相反,此插件可以在您的应用运行时通过导航您的位置来提供更准确和实时的地理围栏。

特性

  • Geofence可以有多个半径。
  • Geofence可以看到设备进入半径时发生的活动。
  • GeofenceService可以在实时操作中执行地理围栏并捕获错误。
  • GeofenceService可以使用WillStartForegroundTask小部件在后台运行。

注意: 此插件基于圆形地理围栏进行地理围栏。如果您想要创建多边形地理围栏,建议使用此插件

开始使用

要在您的项目中使用此插件,将其添加到pubspec.yaml文件中作为依赖项。例如:

dependencies:
  geofence_service_in_app: ^3.6.3

在添加了geofence_service_in_app插件后,我们需要为插件指定特定于平台的权限和服务,以使其正常工作。

Android

由于地理围栏基于位置操作,我们需要在AndroidManifest.xml文件中添加以下权限。打开AndroidManifest.xml文件,并在<manifest><application>标签之间指定它们。

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

如果要使服务在后台运行,请添加以下权限。如果您的项目支持Android 10,请确保添加ACCESS_BACKGROUND_LOCATION权限。

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

<application>标签内指定服务如下:

<service
    android:name="com.pravera.flutter_foreground_task.service.ForegroundService"
    android:foregroundServiceType="location"
    android:stopWithTask="true" />

此插件的最大特点是可以在地理围栏期间知道用户活动。请在<manifest>标签中指定权限使用情况。

<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="com.google.android.gms.permission.ACTIVITY_RECOGNITION" />
<uses-permission android:name="android.permission.ACTIVITY_RECOGNITION" />

iOS

与Android平台一样,地理围栏基于位置操作,我们需要添加以下描述。打开ios/Runner/Info.plist文件并在<dict>标签内指定它们。

<key>NSLocationWhenInUseUsageDescription</key>
<string>Used to provide geofence service.</string>

如果要使服务在后台运行,请添加以下描述。

<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>Used to provide geofence services in the background.</string>
<key>NSLocationAlwaysUsageDescription</key>
<string>Used to provide geofence services in the background.</string>
<key>UIBackgroundModes</key>
<array>
    <string>fetch</string>
    <string>location</string>
</array>

为了检测用户活动的变化,请添加以下描述。

<key>NSMotionUsageDescription</key>
<string>Used to recognize user activity information.</string>

可选)如果要在应用进入后台时显示通知,需要打开ios/Runner/AppDelegate文件并设置以下内容:

Objective-C:

@implementation AppDelegate

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

  // here
  if (@available(iOS 10.0, *)) {
    [UNUserNotificationCenter currentNotificationCenter].delegate = (id<UNUserNotificationCenterDelegate>) self;
  }

  return [super application:application didFinishLaunchingWithOptions:launchOptions];
}

@end

Swift:

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

    // here
    if #available(iOS 10.0, *) {
      UNUserNotificationCenter.current().delegate = self as? UNUserNotificationCenterDelegate
    }

    return super.application(application, didFinishLaunchingWithOptions: launchOptions)
  }
}

如何使用

  1. 创建一个GeofenceService实例并设置选项。GeofenceService.instance.setup()提供了以下选项:

    • interval: 检查地理围栏状态的时间间隔(毫秒)。默认值为5000
    • accuracy: 地理围栏误差范围(米)。默认值为100
    • loiteringDelayMs: 设置GeofenceStatus.ENTERGeofenceStatus.DWELL之间的延迟(毫秒)。默认值为300000
    • statusChangeDelayMs: 设置状态变化延迟(毫秒)。当位置接近地理围栏边界时,可能会频繁调用GeofenceStatus.ENTERGeofenceStatus.EXIT事件。使用此选项可以在此时最小化事件调用。如果选项值太大,则无法实现实时地理围栏,所以请谨慎使用。默认值为10000
    • useActivityRecognition: 是否使用活动识别API。默认值为true
    • allowMockLocations: 是否允许模拟位置。默认值为false
    • printDevLog: 是否显示开发人员日志。如果此值设置为true,则可以查看地理围栏服务活动(启动、停止等)的日志。它在发布模式下不起作用。默认值为false
    • geofenceRadiusSortType: 设置地理围栏半径的排序类型。默认值为GeofenceRadiusSortType.DESC
// 创建一个 [GeofenceService] 实例并设置选项。
final _geofenceService = GeofenceService.instance.setup(
    interval: 5000,
    accuracy: 100,
    loiteringDelayMs: 60000,
    statusChangeDelayMs: 10000,
    useActivityRecognition: true,
    allowMockLocations: false,
    printDevLog: false,
    geofenceRadiusSortType: GeofenceRadiusSortType.DESC);
  1. 创建一个GeofenceGeofenceRadius列表。GeofenceGeofenceRadius提供了以下参数:

    • id: GeofenceGeofenceRadius的标识符。
    • data: GeofenceGeofenceRadius的自定义数据。
    • latitude: 地理围栏中心的纬度。
    • longitude: 地理围栏中心的经度。
    • radius: Geofence的半径。
    • length: 半径的长度(米)。最佳结果应在半径100到150米之间设置。如果有Wi-Fi可用,可以设置为20到40米。
// 创建一个 [Geofence] 列表。
final _geofenceList = <Geofence>[
  Geofence(
    id: 'place_1',
    latitude: 35.103422,
    longitude: 129.036023,
    radius: [
      GeofenceRadius(id: 'radius_100m', length: 100),
      GeofenceRadius(id: 'radius_25m', length: 25),
      GeofenceRadius(id: 'radius_250m', length: 250),
      GeofenceRadius(id: 'radius_200m', length: 200),
    ],
  ),
  Geofence(
    id: 'place_2',
    latitude: 35.104971,
    longitude: 129.034851,
    radius: [
      GeofenceRadius(id: 'radius_25m', length: 25),
      GeofenceRadius(id: 'radius_100m', length: 100),
      GeofenceRadius(id: 'radius_200m', length: 200),
    ],
  ),
];
  1. 注册监听器并调用GeofenceService.instance.start()
// 当地理围栏状态发生变化时调用此函数。
Future<void> _onGeofenceStatusChanged(
    Geofence geofence,
    GeofenceRadius geofenceRadius,
    GeofenceStatus geofenceStatus,
    Location location) async {
  print('geofence: ${geofence.toJson()}');
  print('geofenceRadius: ${geofenceRadius.toJson()}');
  print('geofenceStatus: ${geofenceStatus.toString()}');
  _geofenceStreamController.sink.add(geofence);
}

// 当活动发生变化时调用此函数。
void _onActivityChanged(Activity prevActivity, Activity currActivity) {
  print('prevActivity: ${prevActivity.toJson()}');
  print('currActivity: ${currActivity.toJson()}');
  _activityStreamController.sink.add(currActivity);
}

// 当位置发生变化时调用此函数。
void _onLocationChanged(Location location) {
  print('location: ${location.toJson()}');
}

// 当服务启动以来发生位置服务状态变化时调用此函数。
void _onLocationServicesStatusChanged(bool status) {
  print('isLocationServicesEnabled: $status');
}

// 用于处理服务中发生的错误。
void _onError(error) {
  final errorCode = getErrorCodesFromError(error);
  if (errorCode == null) {
    print('Undefined error: $error');
    return;
  }

  print('ErrorCode: $errorCode');
}

@override
void initState() {
  super.initState();
  WidgetsBinding.instance.addPostFrameCallback((_) {
    _geofenceService.addGeofenceStatusChangeListener(_onGeofenceStatusChanged);
    _geofenceService.addLocationChangeListener(_onLocationChanged);
    _geofenceService.addLocationServicesStatusChangeListener(_onLocationServicesStatusChanged);
    _geofenceService.addActivityChangeListener(_onActivityChanged);
    _geofenceService.addStreamErrorListener(_onError);
    _geofenceService.start(_geofenceList).catchError(_onError);
  });
}
  1. 为了在Android平台上进行后台执行,添加WillStartForegroundTask小部件。WillStartForegroundTask提供了以下选项:

    • onWillStart: 被调用来询问是否要开始前台任务。
    • notificationOptions: 通知详细设置的可选值。
    • notificationTitle: 将在通知中显示的标题。
    • notificationText: 将在通知中显示的文本。
    • child: 包含Scaffold小部件的子小部件。
@override
Widget build(BuildContext context) {
  return MaterialApp(
    // 当尝试最小化或关闭应用时,用于开始前台任务的小部件。
    // 在[Scaffold]小部件之上声明。
    home: WillStartForegroundTask(
      onWillStart: () async {
        // 您可以添加一个前台任务开始条件。
        return _geofenceService.isRunningService;
      },
      androidNotificationOptions: AndroidNotificationOptions(
        channelId: 'geofence_service_in_app_notification_channel',
        channelName: 'Geofence Service Notification',
        channelDescription: 'This notification appears when the geofence service is running in the background.',
        channelImportance: NotificationChannelImportance.LOW,
        priority: NotificationPriority.LOW,
        isSticky: false,
      ),
      iosNotificationOptions: const IOSNotificationOptions(),
      notificationTitle: 'Geofence Service is running',
      notificationText: 'Tap to return to the app',
      child: Scaffold(
        appBar: AppBar(
          title: const Text('Geofence Service'),
          centerTitle: true,
        ),
        body: _buildContentView(),
      ),
    ),
  );
}
  1. 若要在服务运行时添加或移除Geofence,请使用以下功能:
_geofenceService.addGeofence(Object);
_geofenceService.addGeofenceList(List);
_geofenceService.removeGeofence(Object);
_geofenceService.removeGeofenceList(List);
_geofenceService.removeGeofenceById(String);
_geofenceService.clearGeofenceList();
  1. 如果要暂停或恢复服务,请使用以下功能。
_geofenceService.pause();
_geofenceService.resume();
  1. 当您完成使用服务时,取消注册监听器并调用GeofenceService.instance.stop()
_geofenceService.removeGeofenceStatusChangeListener(_onGeofenceStatusChanged);
_geofenceService.removeLocationChangeListener(_onLocationChanged);
_geofenceService.removeLocationServicesStatusChangeListener(_onLocationServicesStatusChanged);
_geofenceService.removeActivityChangeListener(_onActivityChanged);
_geofenceService.removeStreamErrorListener(_onError);
_geofenceService.clearAllListeners();
_geofenceService.stop();

更多关于Flutter地理围栏服务插件geofence_service_in_app的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter地理围栏服务插件geofence_service_in_app的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是如何在Flutter项目中集成和使用geofence_service_in_app插件的示例代码。这个插件允许你在Flutter应用中实现地理围栏功能。以下步骤将指导你如何设置和使用这个插件。

1. 添加依赖

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

dependencies:
  flutter:
    sdk: flutter
  geofence_service_in_app: ^最新版本号  # 请替换为最新的版本号

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

2. 配置Android和iOS权限

由于地理围栏功能需要位置权限,你需要在Android和iOS项目中配置相应的权限。

Android

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

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

iOS

ios/Runner/Info.plist中添加以下权限:

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

3. 请求位置权限

在你的Flutter代码中,请求位置权限:

import 'package:permission_handler/permission_handler.dart';

Future<void> requestLocationPermission() async {
  var status = await Permission.locationWhenInUse.status;
  if (!status.isGranted) {
    var result = await Permission.locationWhenInUse.request();
    if (!result.isGranted) {
      // 处理权限被拒绝的情况
      return;
    }
  }
}

注意:你需要添加permission_handler依赖来处理权限请求。

4. 使用geofence_service_in_app插件

以下是如何使用geofence_service_in_app插件来添加和监听地理围栏的示例代码:

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

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

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

class _MyAppState extends State<MyApp> {
  GeofenceService _geofenceService = GeofenceService();

  @override
  void initState() {
    super.initState();
    _initGeofence();
    _listenToGeofenceEvents();
  }

  Future<void> _initGeofence() async {
    // 添加一个地理围栏
    var geofence = Geofence(
      radius: 100.0, // 半径,单位:米
      latitude: 37.7853889, // 纬度
      longitude: -122.4056973, // 经度
      identifier: "my_geofence",
      transitionType: TransitionType.enter | TransitionType.exit,
    );

    await _geofenceService.addOrUpdate(geofence);
    await _geofenceService.startMonitoring();
  }

  void _listenToGeofenceEvents() {
    _geofenceService.geofenceStatusStream.listen((event) {
      if (event is GeofenceStatusEnter) {
        print("Entered geofence: ${event.geofence.identifier}");
      } else if (event is GeofenceStatusExit) {
        print("Exited geofence: ${event.geofence.identifier}");
      } else if (event is GeofenceStatusStay) {
        print("Stayed within geofence: ${event.geofence.identifier}");
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Geofence Example'),
        ),
        body: Center(
          child: Text('Check the console for geofence events'),
        ),
      ),
    );
  }
}

5. 运行应用

确保所有配置正确后,运行你的Flutter应用。你应该能够在控制台中看到地理围栏事件的日志输出。

这个示例展示了如何集成geofence_service_in_app插件,添加地理围栏,并监听进入、退出和停留事件。根据你的需求,你可以进一步自定义和扩展这个示例。

回到顶部