native_geofence
使用原生 iOS 與 Android API 的電池高效 Flutter 地理圍欄。
使用原生 iOS 與 Android API 的電池高效 Flutter 地理圍欄。
{"sdk":"flutter"}^1.17.0^2.1.8{"sdk":"flutter"}^6.0.0^26.3.4以下為英文專案原文快照,最新內容請造訪 GitHub。
Battery efficient Flutter geofencing plugin that uses native iOS and Android APIs.
This plugin works with both Android Kotlin setups, so follow the one that matches your toolchain:
kotlin-android Gradle plugin yourself — AGP 9 rejects an explicitly applied Kotlin plugin. See Flutter's built-in Kotlin migration guide.1.9.25 (see this guide). The latest Kotlin version can be found here.The example app demonstrates the AGP 8 setup, with comments in its Gradle files noting the AGP 9 difference.
NOTE: You may also need Gradle 8+ to use this plugin. See this issue.
minSdkVersion to 23 or above.Explanation: If you need to support prior Android builds it might be possible to accommodate this. Please send a PR or file a bug.
See the example plugin for a full demonstration.
AndroidManifest.xml add the following lines right before </application>:<!-- Used by plugin: native_geofence -->
<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"></action>
</intent-filter>
</receiver>
<service android:name="com.chunkytofustudios.native_geofence.NativeGeofenceForegroundService"
android:permission="android.permission.BIND_JOB_SERVICE" android:exported="true"/>
Explanation: The NativeGeofenceBroadcastReceiver is used to listen for geofence events the Android OS sends. The NativeGeofenceRebootBroadcastReceiver runs after device reboot and re-registers geofences (this is required since Android doesn't retain them). Finally, NativeGeofenceForegroundService is utilized when you want to run a foreground service when handling a geofence callback.
<application ... line:<!-- Used by plugin: native_geofence -->
<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"/>
Explanation: The coarse and fine locations are required to create a geofence. The background location permission is also required for geofence creation on Android API level 29+. The boot completed permission is required to re-register geofences after reboot. The wake lock permission is only required if you need to run foreground services to respond to geofence events.
If you want to perform any heavy work when a Geofence triggers (within the Geofence callback), such as calling a backend API, you will need to ask the user to disable battery optimization for your app.
You can do so by using the disable_battery_optimization package. You can find a code sample here.
If your app is using Objective-C you will need to migrate to Swift. Here is a guide you can follow.
Info.plist add the following key-value pairs:<key>NSLocationWhenInUseUsageDescription</key>
<string>USER_VISIBLE_STRING__DESCRIBE_HOW_YOUR_APP_USES_LOCATION.</string>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>USER_VISIBLE_STRING__DESCRIBE_HOW_YOUR_APP_USES_BACKGROUND_LOCATION.</string>
Explanation: The in-use location permission is required to create geofences. The always location permission is required if you want to be notified of geofence events when your app isn't running.
NativeGeofencePlugin:In your AppDelegate.swift file import the plugin:
import native_geofence
and add the following near the top of the application function:
// Used by plugin: native_geofence
NativeGeofencePlugin.setPluginRegistrantCallback { registry in
GeneratedPluginRegistrant.register(with: registry)
}
In your AppDelegate.m file import the plugin and define the registerPlugins function:
#import <native_geofence/NativeGofencePlugin.h>
void registerPlugins(NSObject<FlutterPluginRegistry>* registry) {
[GeneratedPluginRegistrant registerWithRegistry:registry];
}
and add the following within the application(_:didFinishLaunchingWithOptions:) function:
// Used by plugin: native_geofence
[NativeGofencePlugin setPluginRegistrantCallback:registerPlugins];
14.0 or above.You can do so in your Podfile by adding the line platform :ios, '14.0'.
Explanation: If you need to support prior iOS builds it might be possible to accommodate this. Please send a PR or file a bug.
See the example plugin for a full demonstration.
Before accesing any methods ensure you initialize the plugin:
await NativeGeofenceManager.instance.initialize();
This plugin does not deal with obtaining permissions from the user. Please use a 3rd party plugin, such as permission_handler for that.
As noted in the setup section you will need to obtain the following permissions:
Permission.locationPermission.locationAlways: if you want to be notified of geofence events when your app isn't runningFirst, define your geofence parameters using the Geofence class, for example:
Note: The ID must be unqiue. Please see the API reference for details.
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),
),
);
Next, create a top-level function that has the @pragma('vm:entry-point') annotation; this will act as your geofence callback/handler:
Note: You can (optional) specify a unique callback function for each geofence.
@pragma('vm:entry-point')
Future<void> geofenceTriggered(GeofenceCallbackParams params) async {
debugPrint('Geofence triggered with params: $params');
}
Finally, create the geofence:
await NativeGeofenceManager.instance.createGeofence(zone1, geofenceTriggered);
If you need to access certain APIs or run a long job in your geofence callback you can promote the runner to a foreground service. You have access to the following functions when running within a geofence callback:
NativeGeofenceBackgroundManager.instance.promoteToForeground();
// Do a lot of work or access live location?
NativeGeofenceBackgroundManager.instance.demoteToBackground();
Note: Most tasks that complete in a few seconds, such as sending a notification, don't require your callback to run in a foreground service.
Warning: This functionality is not well tested. Please report any bugs you find.
You can see which geofences are currently active using:
final List<ActiveGeofence> myGeofences = await NativeGeofenceManager.instance.getRegisteredGeofences();
print('There are ${myGeofences.length} active geofences.')
You have multiple options to stop listenning for geofence events:
// Remove a single geofence:
await NativeGeofenceManager.instance.removeGeofenceById('zone1');
// Remove all geofences:
await NativeGeofenceManager.instance.removeAllGeofences();
All errors thrown by this plugin are wrapped in NativeGeofenceException.
Each exception will contain an error code, please see the API reference a description of each of them.
Ensure you catch this exception and take the neccesary action. For example you might:
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 occured: message=${e.message}, detail=${e.details}, stackTrace=${e.stacktrace}')
return
}
// Handle other cases.
}
The provided example app demonstrates how to request permissions, register geofences, and send notifications when geofence events occur.
This plugin is based off of bkonyi/FlutterGeofencing and uses code snippets from flutter_workmanager. It was inspired by 525k.io's geofence_foreground_service plugin.
Please file any issues, bugs, or feature requests at GitHub.
Pull requests are welcome.
This plugin is developed by Chunky Tofu Studios.
You can support us by checking out our apps!
For commercial support please reach out to hello@chunkytofustudios.com.