Flutter地理围栏功能插件native_geofence的使用

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

Flutter地理围栏功能插件native_geofence的使用

插件介绍

native_geofence 是一个高效的Flutter地理围栏插件,它利用了iOS和Android的原生API。地理围栏允许您的应用程序在用户进入或离开特定地理区域时收到通知。这可以用于设置提醒、跟踪位置等场景。

功能特点

  • 平台支持:基于iOS的CLLocationManager和Android的GeofencingClient
  • 事件监听:创建地理围栏并接收进入/退出/停留事件的通知
  • 工作状态:支持应用在前台、后台或终止状态下运行
  • 重启后重新注册:设备重启后自动重新注册地理围栏
  • 获取已注册的地理围栏
  • [Android] 前台服务处理地理围栏事件

环境配置

Android 配置

  1. AndroidManifest.xml 文件中添加以下代码段:

    <receiver android:name="com.chunkytofustudios.native_geofence.receivers.NativeGeofenceBroadcastReceiver"
              android:exported="true"/>
    <receiver android:name="com.chunkytofustudios.native_geofence.receivers.NativeGeofenceRebootBroadcastReceiver"
              android:exported="true">
        <intent-filter>
            <action android:name="android.intent.action.BOOT_COMPLETED"/>
        </intent-filter>
    </receiver>
    <service android:name="com.chunkytofustudios.native_geofence.NativeGeofenceForegroundService"
             android:permission="android.permission.BIND_JOB_SERVICE" android:exported="true"/>
    
  2. 添加必要的权限:

    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
    <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
    <uses-permission android:name="android.permission.WAKE_LOCK"/>
    
  3. 设置 minSdkVersion 为26或更高版本。

iOS 配置

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

    <key>NSLocationWhenInUseUsageDescription</key>
    <string>描述您的应用如何使用位置信息。</string>
    <key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
    <string>描述您的应用如何使用后台位置信息。</string>
    
  2. 更新 AppDelegate.swiftAppDelegate.m 文件以调用 NativeGeofencePlugin

  3. 将 iOS 版本设置为14.0或更高版本。

使用示例

初始化插件

await NativeGeofenceManager.instance.initialize();

获取权限

请确保已经通过第三方插件(如permission_handler)请求了以下权限:

  • Permission.location
  • Permission.locationAlways(如果需要在应用未运行时接收地理围栏事件)

创建地理围栏

定义地理围栏参数并创建地理围栏:

final zone1 = Geofence(
  id: 'zone1',
  location: Location(latitude: 40.75798, longitude: -73.98554), // Times Square
  radiusMeters: 500,
  triggers: {
    GeofenceEvent.enter,
    GeofenceEvent.exit,
    GeofenceEvent.dwell,
  },
  iosSettings: IosGeofenceSettings(
    initialTrigger: true,
  ),
  androidSettings: AndroidGeofenceSettings(
    initialTriggers: {GeofenceEvent.enter},
    expiration: const Duration(days: 7),
    loiteringDelay: const Duration(minutes: 5),
    notificationResponsiveness: const Duration(minutes: 5),
  ),
);

@pragma('vm:entry-point')
Future<void> geofenceTriggered(GeofenceCallbackParams params) async {
  debugPrint('Geofence triggered with params: $params');
}

await NativeGeofenceManager.instance.createGeofence(zone1, geofenceTriggered);

获取已注册的地理围栏

final List<ActiveGeofence> myGeofences = await NativeGeofenceManager.instance.getRegisteredGeofences();
print('There are ${myGeofences.length} active geofences.');

移除地理围栏

// 移除单个地理围栏
await NativeGeofenceManager.instance.removeGeofenceById('zone1');

// 移除所有地理围栏
await NativeGeofenceManager.instance.removeAllGeofences();

错误处理

捕获并处理可能抛出的 NativeGeofenceException 异常:

try {
  await NativeGeofenceManager.instance.createGeofence(zone1, geofenceTriggered);
} on NativeGeofenceException catch (e) {
  if (e.code == NativeGeofenceErrorCode.missingLocationPermission) {
    print('Did the user grant us the location permission yet?');
    return;
  }
  if (e.code == NativeGeofenceErrorCode.pluginInternal) {
    print('Some internal error occurred: message=${e.message}, detail=${e.details}, stackTrace=${e.stacktrace}');
    return;
  }
  // Handle other cases.
}

完整示例代码

以下是包含初始化、创建地理围栏及UI展示的完整示例代码:

import 'dart:async';
import 'dart:isolate';
import 'dart:ui';

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

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

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

class _MyAppState extends State<MyApp> {
  String geofenceState = 'N/A';
  ReceivePort port = ReceivePort();

  @override
  void initState() {
    super.initState();
    IsolateNameServer.registerPortWithName(port.sendPort, 'native_geofence_send_port');
    port.listen((dynamic data) {
      debugPrint('Event: $data');
      setState(() {
        geofenceState = data;
      });
    });
    initPlatformState();
  }

  Future<void> initPlatformState() async {
    debugPrint('Initializing...');
    await NativeGeofenceManager.instance.initialize();
    debugPrint('Initialization done');
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Native Geofence'),
        ),
        body: Container(
          padding: const EdgeInsets.all(20.0),
          child: SingleChildScrollView(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                Text('Current state: $geofenceState'),
                const SizedBox(height: 20),
                ElevatedButton(
                  onPressed: () async {
                    final zone1 = Geofence(
                      id: 'zone1',
                      location: Location(latitude: 40.75798, longitude: -73.98554), // Times Square
                      radiusMeters: 500,
                      triggers: {
                        GeofenceEvent.enter,
                        GeofenceEvent.exit,
                        GeofenceEvent.dwell,
                      },
                      iosSettings: IosGeofenceSettings(
                        initialTrigger: true,
                      ),
                      androidSettings: AndroidGeofenceSettings(
                        initialTriggers: {GeofenceEvent.enter},
                        expiration: const Duration(days: 7),
                        loiteringDelay: const Duration(minutes: 5),
                        notificationResponsiveness: const Duration(minutes: 5),
                      ),
                    );

                    @pragma('vm:entry-point')
                    Future<void> geofenceTriggered(GeofenceCallbackParams params) async {
                      debugPrint('Geofence triggered with params: $params');
                    }

                    try {
                      await NativeGeofenceManager.instance.createGeofence(zone1, geofenceTriggered);
                      setState(() {
                        geofenceState = 'Geofence created successfully';
                      });
                    } on NativeGeofenceException catch (e) {
                      setState(() {
                        geofenceState = 'Error creating geofence: ${e.message}';
                      });
                    }
                  },
                  child: const Text('Create Geofence'),
                ),
              ],
            ),
          ),
        ),
      ),
    );
  }
}

这个完整的示例展示了如何初始化插件、创建地理围栏,并在界面上显示当前的状态。希望这些信息能帮助您更好地理解和使用 native_geofence 插件!


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

1 回复

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


当然,以下是如何在Flutter项目中集成并使用native_geofence插件来实现地理围栏功能的示例代码。这个插件允许你在用户进入或离开指定区域时接收通知。

第一步:添加依赖

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

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

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

第二步:配置权限

在你的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_COARSE_LOCATION" />
    <uses-permission android:name="android.permission.ACTIVITY_RECOGNITION" />

    <!-- 其他配置 -->

</manifest>

对于iOS,在Info.plist中添加以下权限:

<key>NSLocationAlwaysUsageDescription</key>
<string>需要您的位置信息来检测地理围栏</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>需要您的位置信息来检测地理围栏</string>
<key>NSMotionUsageDescription</key>
<string>需要活动识别权限来优化地理围栏检测</string>

第三步:实现地理围栏功能

在你的Flutter项目中,创建一个Dart文件(例如geofence_service.dart),并添加以下代码来配置和使用地理围栏:

import 'package:flutter/services.dart';
import 'package:native_geofence/native_geofence.dart';

class GeofenceService {
  static const platform = MethodChannel('com.example.yourapp/geofence');

  static Future<void> configureGeofence() async {
    try {
      // 配置一个地理围栏
      var geofence = Geofence(
        id: "my_geofence_1",
        latitude: 37.7853889,
        longitude: -122.4056973,
        radius: 1000.0, // 半径1000米
        transitionType: TransitionType.ENTER | TransitionType.EXIT,
        loiteringDelay: 300, // 徘徊延迟300秒
        notification: GeofenceNotification(
          title: "地理围栏通知",
          text: "您已进入或离开了指定区域",
          openAction: OpenAction(
            label: "打开应用",
            id: "open_app",
          ),
        ),
      );

      // 添加地理围栏
      await NativeGeofence.addGeofence(geofence);
      print("Geofence added successfully");
    } catch (e) {
      print("Error adding geofence: $e");
    }
  }

  static Future<void> initializeListeners() async {
    try {
      // 监听地理围栏事件
      NativeGeofence.geofenceStatusStream.listen((event) {
        if (event.containsKey("geofencesAdded")) {
          print("Added geofences: ${event["geofencesAdded"]}");
        }
        if (event.containsKey("geofencesRemoved")) {
          print("Removed geofences: ${event["geofencesRemoved"]}");
        }
        if (event.containsKey("geofenceTransition")) {
          var transition = event["geofenceTransition"] as Map<String, dynamic>;
          print("Geofence transition: ${transition}");
        }
      });
    } catch (e) {
      print("Error initializing listeners: $e");
    }
  }
}

第四步:在应用中调用

在你的主应用文件(例如main.dart)中,调用上述服务来配置地理围栏并初始化监听器:

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

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('地理围栏示例'),
        ),
        body: Center(
          child: ElevatedButton(
            onPressed: () async {
              await GeofenceService.configureGeofence();
              await GeofenceService.initializeListeners();
            },
            child: Text('配置地理围栏'),
          ),
        ),
      ),
    );
  }
}

注意事项

  1. 确保在真实设备或支持位置模拟的模拟器上测试此功能。
  2. 插件的初始化和权限请求可能需要额外的处理,尤其是在iOS上,你可能需要在运行时请求位置权限。
  3. native_geofence插件的API可能会随着版本更新而变化,请参考最新的官方文档进行适配。

以上代码提供了一个基本的地理围栏功能实现,你可以根据需要进行扩展和修改。

回到顶部