Enable background geolocation updates

Enhanced geolocation plugin to support background updates. Added the `requestUpdatesInBackground` option to `watchPosition` and `requestPermissions` functions. Updated iOS handler to request appropriate location permissions based on this setting, and configured location manager for background updates. This change enables apps to continuously track location, improving functionality for applications requiring persistent geolocation data. Also introduced a default permissions configuration for the plugin.
pull/1889/head
Bradley Leatherwood 9 months ago
parent f445c704a1
commit 0ac7adfd10
No known key found for this signature in database

@ -93,7 +93,7 @@ export type PositionOptions = {
}
export async function watchPosition(
options: PositionOptions,
options: PositionOptions & {requestUpdatesInBackground?: boolean},
cb: (location: Position | null, error?: string) => void
): Promise<number> {
const channel = new Channel<Position | string>()
@ -106,6 +106,7 @@ export async function watchPosition(
}
await invoke('plugin:geolocation|watch_position', {
options,
requestUpdatesInBackground: options.requestUpdatesInBackground ?? false,
channel
})
return channel.id
@ -130,9 +131,11 @@ export async function checkPermissions(): Promise<PermissionStatus> {
}
export async function requestPermissions(
permissions: PermissionType[] | null
permissions: PermissionType[] | null,
requestUpdatesInBackground: boolean = false
): Promise<PermissionStatus> {
return await invoke('plugin:geolocation|request_permissions', {
permissions
permissions,
requestUpdatesInBackground
})
}

@ -14,6 +14,7 @@ class GetPositionArgs: Decodable {
class WatchPositionArgs: Decodable {
let options: GetPositionArgs
let request_updates_in_background: Bool
let channel: Channel
}
@ -21,9 +22,20 @@ class ClearWatchArgs: Decodable {
let channelId: UInt32
}
enum PermissionType: String, Decodable {
case location
case coarseLocation
}
class RequestPermissionsArgs: Decodable {
let permissions: [PermissionType]
let requestUpdatesInBackground: Bool
}
class GeolocationPlugin: Plugin, CLLocationManagerDelegate {
private let locationManager = CLLocationManager()
private var isUpdatingLocation: Bool = false
private var backgroundUpdatesRequested: Bool = false
private var permissionRequests: [Invoke] = []
private var positionRequests: [Invoke] = []
private var watcherChannels: [Channel] = []
@ -61,6 +73,8 @@ class GeolocationPlugin: Plugin, CLLocationManagerDelegate {
@objc public func watchPosition(_ invoke: Invoke) throws {
let args = try invoke.parseArgs(WatchPositionArgs.self)
self.backgroundUpdatesRequested = args.request_updates_in_background;
self.watcherChannels.append(args.channel)
DispatchQueue.main.async {
@ -70,12 +84,28 @@ class GeolocationPlugin: Plugin, CLLocationManagerDelegate {
self.locationManager.desiredAccuracy = kCLLocationAccuracyKilometer
}
// TODO: Use the authorizationStatus instance property with locationManagerDidChangeAuthorization(_:) instead.
if CLLocationManager.authorizationStatus() == .notDetermined {
if self.backgroundUpdatesRequested {
self.locationManager.requestAlwaysAuthorization()
} else {
self.locationManager.requestWhenInUseAuthorization()
}
} else {
if CLLocationManager.authorizationStatus() == .authorizedWhenInUse && self.backgroundUpdatesRequested {
self.locationManager.requestAlwaysAuthorization()
} else {
self.locationManager.startUpdatingLocation()
self.isUpdatingLocation = true
// Enable background updates if enabled
if self.backgroundUpdatesRequested {
self.locationManager.allowsBackgroundLocationUpdates = true
self.locationManager.pausesLocationUpdatesAutomatically = false
self.locationManager.showsBackgroundLocationIndicator = true
}
}
}
}
@ -125,9 +155,19 @@ class GeolocationPlugin: Plugin, CLLocationManagerDelegate {
// TODO: Use the authorizationStatus instance property with locationManagerDidChangeAuthorization(_:) instead.
if CLLocationManager.authorizationStatus() == .notDetermined {
self.permissionRequests.append(invoke)
do {
let args = try invoke.parseArgs(RequestPermissionsArgs.self)
DispatchQueue.main.async {
self.locationManager.requestWhenInUseAuthorization()
if args.requestUpdatesInBackground {
// Request background permission if requested
self.locationManager.requestAlwaysAuthorization()
self.backgroundUpdatesRequested = true
}
}
} catch {
invoke.reject(error.localizedDescription)
}
} else {
checkPermissions(invoke)
@ -224,6 +264,11 @@ class GeolocationPlugin: Plugin, CLLocationManagerDelegate {
private func stopUpdating() {
self.locationManager.stopUpdatingLocation()
self.isUpdatingLocation = false
if self.backgroundUpdatesRequested {
self.locationManager.allowsBackgroundLocationUpdates = false
self.locationManager.pausesLocationUpdatesAutomatically = true
self.locationManager.showsBackgroundLocationIndicator = false
}
}
private func convertLocation(_ location: CLLocation) -> JsonObject {

@ -0,0 +1,3 @@
[default]
description = "Default permissions for the plugin"
permissions = ["allow-request-permissions", "allow-check-permissions", "allow-clear-watch", "allow-watch-position", "allow-get-current-position"]

@ -20,9 +20,10 @@ pub(crate) async fn get_current_position<R: Runtime>(
pub(crate) async fn watch_position<R: Runtime>(
app: AppHandle<R>,
options: PositionOptions,
request_updates_in_background: bool,
channel: Channel,
) -> Result<()> {
app.geolocation().watch_position_inner(options, channel)
app.geolocation().watch_position_inner(options, channel, request_updates_in_background)
}
#[command]
@ -42,6 +43,7 @@ pub(crate) async fn check_permissions<R: Runtime>(app: AppHandle<R>) -> Result<P
pub(crate) async fn request_permissions<R: Runtime>(
app: AppHandle<R>,
permissions: Option<Vec<PermissionType>>,
request_updates_in_background: bool,
) -> Result<PermissionStatus> {
app.geolocation().request_permissions(permissions)
app.geolocation().request_permissions(permissions, request_updates_in_background)
}

@ -32,6 +32,7 @@ impl<R: Runtime> Geolocation<R> {
pub fn watch_position<F: Fn(WatchEvent) + Send + Sync + 'static>(
&self,
options: PositionOptions,
request_updates_in_background: bool,
callback: F,
) -> crate::Result<u32> {
let channel = Channel::new(move |event| {
@ -51,7 +52,7 @@ impl<R: Runtime> Geolocation<R> {
});
let id = channel.id();
self.watch_position_inner(options, channel)?;
self.watch_position_inner(options, request_updates_in_background, channel)?;
Ok(id)
}
@ -59,6 +60,7 @@ impl<R: Runtime> Geolocation<R> {
pub(crate) fn watch_position_inner(
&self,
_options: PositionOptions,
_request_updates_in_background: bool,
_callback_channel: Channel,
) -> crate::Result<()> {
Ok(())
@ -75,6 +77,7 @@ impl<R: Runtime> Geolocation<R> {
pub fn request_permissions(
&self,
_permissions: Option<Vec<PermissionType>>,
_request_updates_in_background: bool,
) -> crate::Result<PermissionStatus> {
Ok(PermissionStatus::default())
}

@ -47,6 +47,7 @@ impl<R: Runtime> Geolocation<R> {
pub fn watch_position<F: Fn(WatchEvent) + Send + Sync + 'static>(
&self,
options: PositionOptions,
request_updates_in_background: bool,
callback: F,
) -> crate::Result<u32> {
let channel = Channel::new(move |event| {
@ -66,7 +67,7 @@ impl<R: Runtime> Geolocation<R> {
});
let id = channel.id();
self.watch_position_inner(options, channel)?;
self.watch_position_inner(options, request_updates_in_background, channel)?;
Ok(id)
}
@ -74,10 +75,18 @@ impl<R: Runtime> Geolocation<R> {
pub(crate) fn watch_position_inner(
&self,
options: PositionOptions,
request_updates_in_background: bool,
channel: Channel,
) -> crate::Result<()> {
self.0
.run_mobile_plugin("watchPosition", WatchPayload { options, channel })
.run_mobile_plugin(
"watchPosition",
WatchPayload {
options,
channel,
request_updates_in_background,
},
)
.map_err(Into::into)
}
@ -96,11 +105,15 @@ impl<R: Runtime> Geolocation<R> {
pub fn request_permissions(
&self,
permissions: Option<Vec<PermissionType>>,
request_updates_in_background: bool,
) -> crate::Result<PermissionStatus> {
self.0
.run_mobile_plugin(
"requestPermissions",
serde_json::json!({ "permissions": permissions }),
serde_json::json!({
"permissions": permissions,
"requestUpdatesInBackground": request_updates_in_background,
}),
)
.map_err(Into::into)
}

Loading…
Cancel
Save