@capgo/background-geolocation 7.0.8 → 7.0.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -208,8 +208,8 @@ Configration specific to Android can be made in `strings.xml`:
208
208
 
209
209
  <docgen-index>
210
210
 
211
- * [`addWatcher(...)`](#addwatcher)
212
- * [`removeWatcher(...)`](#removewatcher)
211
+ * [`start(...)`](#start)
212
+ * [`stop()`](#stop)
213
213
  * [`openSettings()`](#opensettings)
214
214
  * [Interfaces](#interfaces)
215
215
 
@@ -1,17 +1,14 @@
1
1
  package com.capgo.capacitor_background_geolocation;
2
2
 
3
3
  import android.Manifest;
4
- import android.app.Notification;
5
4
  import android.app.NotificationChannel;
6
5
  import android.app.NotificationManager;
7
- import android.app.PendingIntent;
8
6
  import android.content.BroadcastReceiver;
9
7
  import android.content.ComponentName;
10
8
  import android.content.Context;
11
9
  import android.content.Intent;
12
10
  import android.content.IntentFilter;
13
11
  import android.content.ServiceConnection;
14
- import android.graphics.Color;
15
12
  import android.location.Location;
16
13
  import android.location.LocationManager;
17
14
  import android.net.Uri;
@@ -68,7 +65,7 @@ public class BackgroundGeolocation extends Plugin {
68
65
  }
69
66
 
70
67
  @PluginMethod(returnType = PluginMethod.RETURN_CALLBACK)
71
- public void addWatcher(final PluginCall call) {
68
+ public void start(final PluginCall call) {
72
69
  if (
73
70
  getPermissionState("location") != PermissionState.GRANTED &&
74
71
  !call.getBoolean("requestPermissions", true)
@@ -77,6 +74,11 @@ public class BackgroundGeolocation extends Plugin {
77
74
  return;
78
75
  }
79
76
 
77
+ if (serviceConnectionFuture != null) {
78
+ call.reject("Service already started", "ALREADY_STARTED");
79
+ return;
80
+ }
81
+
80
82
  if (
81
83
  getPermissionState("location") != PermissionState.GRANTED &&
82
84
  call.getBoolean("requestPermissions", true)
@@ -84,7 +86,7 @@ public class BackgroundGeolocation extends Plugin {
84
86
  call.setKeepAlive(true);
85
87
  requestLocationPermissions(call)
86
88
  .thenRun(() -> {
87
- proceedWithWatcher(call);
89
+ proceedWithStart(call);
88
90
  })
89
91
  .exceptionally(throwable -> {
90
92
  call.reject("User denied location permission", "NOT_AUTHORIZED");
@@ -101,17 +103,18 @@ public class BackgroundGeolocation extends Plugin {
101
103
 
102
104
  // Everything is OK, continuing to adding a watcher
103
105
  call.setKeepAlive(true);
104
- proceedWithWatcher(call);
106
+ proceedWithStart(call);
105
107
  }
106
108
 
107
- private void proceedWithWatcher(PluginCall call) {
109
+ private void proceedWithStart(PluginCall call) {
108
110
  if (call.getBoolean("stale", false)) {
109
111
  fetchLastLocation(call);
110
112
  }
111
113
  getServiceConnection().thenAccept(serviceBinder -> {
112
- serviceBinder.addWatcher(
114
+ serviceBinder.start(
113
115
  call.getCallbackId(),
114
- createBackgroundNotification(call),
116
+ call.getString("backgroundTitle", "Using your location"),
117
+ call.getString("backgroundMessage", ""),
115
118
  call.getFloat("distanceFilter", 0f)
116
119
  );
117
120
  });
@@ -126,67 +129,6 @@ public class BackgroundGeolocation extends Plugin {
126
129
  return locationPermissionFuture;
127
130
  }
128
131
 
129
- private Notification createBackgroundNotification(PluginCall call) {
130
- String backgroundMessage = call.getString("backgroundMessage", "");
131
-
132
- Notification.Builder builder = new Notification.Builder(getContext())
133
- .setContentTitle(call.getString("backgroundTitle", "Using your location"))
134
- .setContentText(backgroundMessage)
135
- .setOngoing(true)
136
- .setPriority(Notification.PRIORITY_HIGH)
137
- .setWhen(System.currentTimeMillis());
138
-
139
- try {
140
- String name = getAppString(
141
- "capacitor_background_geolocation_notification_icon",
142
- "mipmap/ic_launcher"
143
- );
144
- String[] parts = name.split("/");
145
- // It is actually necessary to set a valid icon for the notification to behave
146
- // correctly when tapped. If there is no icon specified, tapping it will open the
147
- // app's settings, rather than bringing the application to the foreground.
148
- builder.setSmallIcon(getAppResourceIdentifier(parts[1], parts[0]));
149
- } catch (Exception e) {
150
- Logger.error("Could not set notification icon", e);
151
- }
152
-
153
- try {
154
- String color = getAppString(
155
- "capacitor_background_geolocation_notification_color",
156
- null
157
- );
158
- if (color != null) {
159
- builder.setColor(Color.parseColor(color));
160
- }
161
- } catch (Exception e) {
162
- Logger.error("Could not set notification color", e);
163
- }
164
-
165
- Intent launchIntent = getContext()
166
- .getPackageManager()
167
- .getLaunchIntentForPackage(getContext().getPackageName());
168
- if (launchIntent != null) {
169
- launchIntent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
170
- builder.setContentIntent(
171
- PendingIntent.getActivity(
172
- getContext(),
173
- 0,
174
- launchIntent,
175
- PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE
176
- )
177
- );
178
- }
179
-
180
- // Set the Channel ID for Android O.
181
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
182
- builder.setChannelId(
183
- BackgroundGeolocationService.class.getPackage().getName()
184
- );
185
- }
186
-
187
- return builder.build();
188
- }
189
-
190
132
  @PermissionCallback
191
133
  private void locationPermissionsCallback(PluginCall call) {
192
134
  if (locationPermissionFuture == null) {
@@ -217,21 +159,19 @@ public class BackgroundGeolocation extends Plugin {
217
159
  }
218
160
 
219
161
  @PluginMethod
220
- public void removeWatcher(PluginCall call) {
221
- String callbackId = call.getString("id");
222
- if (callbackId == null) {
223
- call.reject("Missing id.");
224
- return;
162
+ public void stop(PluginCall call) {
163
+ if (serviceConnectionFuture == null) {
164
+ call.resolve();
225
165
  }
226
-
227
166
  getServiceConnection()
228
167
  .thenAccept(service -> {
229
- service.removeWatcher(callbackId);
168
+ var callbackId = service.stop();
230
169
  PluginCall savedCall = getBridge().getSavedCall(callbackId);
231
170
  if (savedCall != null) {
232
171
  savedCall.release(getBridge());
233
172
  }
234
173
  call.resolve();
174
+ serviceConnectionFuture = null;
235
175
  })
236
176
  .exceptionally(throwable -> {
237
177
  call.reject("Service connection failed: " + throwable.getMessage());
@@ -321,19 +261,6 @@ public class BackgroundGeolocation extends Plugin {
321
261
  }
322
262
  }
323
263
 
324
- // Gets the identifier of the app's resource by name, returning 0 if not found.
325
- private int getAppResourceIdentifier(String name, String defType) {
326
- return getContext()
327
- .getResources()
328
- .getIdentifier(name, defType, getContext().getPackageName());
329
- }
330
-
331
- // Gets a string from the app's strings.xml file, resorting to a fallback if it is not defined.
332
- private String getAppString(String name, String fallback) {
333
- int id = getAppResourceIdentifier(name, "string");
334
- return id == 0 ? fallback : getContext().getString(id);
335
- }
336
-
337
264
  @Override
338
265
  public void load() {
339
266
  super.load();
@@ -346,9 +273,10 @@ public class BackgroundGeolocation extends Plugin {
346
273
  );
347
274
  NotificationChannel channel = new NotificationChannel(
348
275
  BackgroundGeolocationService.class.getPackage().getName(),
349
- getAppString(
276
+ BackgroundGeolocationService.getAppString(
350
277
  "capacitor_background_geolocation_notification_channel_name",
351
- "Background Tracking"
278
+ "Background Tracking",
279
+ getContext()
352
280
  ),
353
281
  NotificationManager.IMPORTANCE_DEFAULT
354
282
  );
@@ -407,21 +335,11 @@ public class BackgroundGeolocation extends Plugin {
407
335
  return serviceConnectionFuture;
408
336
  }
409
337
 
410
- @Override
411
- protected void handleOnResume() {
412
- super.handleOnResume();
413
- }
414
-
415
- @Override
416
- protected void handleOnPause() {
417
- super.handleOnPause();
418
- }
419
-
420
338
  @Override
421
339
  protected void handleOnDestroy() {
422
340
  if (serviceConnectionFuture != null) {
423
341
  serviceConnectionFuture.thenAccept(
424
- BackgroundGeolocationService.LocalBinder::stopService
342
+ BackgroundGeolocationService.LocalBinder::stop
425
343
  );
426
344
  }
427
345
 
@@ -1,16 +1,18 @@
1
1
  package com.capgo.capacitor_background_geolocation;
2
2
 
3
3
  import android.app.Notification;
4
+ import android.app.PendingIntent;
4
5
  import android.app.Service;
5
6
  import android.content.Context;
6
7
  import android.content.Intent;
8
+ import android.graphics.Color;
7
9
  import android.location.LocationListener;
8
10
  import android.location.LocationManager;
9
11
  import android.os.Binder;
12
+ import android.os.Build;
10
13
  import android.os.IBinder;
11
14
  import androidx.localbroadcastmanager.content.LocalBroadcastManager;
12
15
  import com.getcapacitor.Logger;
13
- import java.util.HashSet;
14
16
 
15
17
  // A bound and started service that is promoted to a foreground service
16
18
  // (showing a persistent notification) when the first background watcher is
@@ -24,16 +26,10 @@ public class BackgroundGeolocationService extends Service {
24
26
  // Must be unique for this application.
25
27
  private static final int NOTIFICATION_ID = 28351;
26
28
 
27
- private static class Watcher {
29
+ private String callbackId;
28
30
 
29
- public String id;
30
- public LocationManager client;
31
- public float distanceFilter;
32
- public LocationListener locationCallback;
33
- public Notification backgroundNotification;
34
- }
35
-
36
- private HashSet<Watcher> watchers = new HashSet<>();
31
+ private LocationManager client;
32
+ private LocationListener locationCallback;
37
33
 
38
34
  @Override
39
35
  public IBinder onBind(Intent intent) {
@@ -46,59 +42,44 @@ public class BackgroundGeolocationService extends Service {
46
42
  // service is terminated immediately.
47
43
  @Override
48
44
  public boolean onUnbind(Intent intent) {
49
- for (Watcher watcher : watchers) {
50
- watcher.client.removeUpdates(watcher.locationCallback);
51
- }
52
- watchers = new HashSet<>();
45
+ client.removeUpdates(locationCallback);
53
46
  stopSelf();
54
47
  return false;
55
48
  }
56
49
 
57
- private void requestLocationUpdates(Watcher watcher) {
58
- try {
59
- watcher.client.requestLocationUpdates(
60
- LocationManager.GPS_PROVIDER,
61
- 1000,
62
- watcher.distanceFilter,
63
- watcher.locationCallback
64
- );
65
- } catch (SecurityException ignore) {
66
- // According to Android Studio, this method can throw a Security Exception if
67
- // permissions are not yet granted. Rather than check the permissions, which is fiddly,
68
- // we simply ignore the exception.
69
- }
70
- }
71
-
72
50
  // Handles requests from the activity.
73
51
  public class LocalBinder extends Binder {
74
52
 
75
- void addWatcher(
53
+ void start(
76
54
  final String id,
77
- Notification backgroundNotification,
55
+ final String notificationTitle,
56
+ final String notificationMessage,
78
57
  float distanceFilter
79
58
  ) {
80
- LocationManager locationManager = (LocationManager) getSystemService(
81
- Context.LOCATION_SERVICE
82
- );
59
+ client = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
60
+ callbackId = id;
83
61
 
84
- LocationListener listener = location -> {
62
+ locationCallback = location -> {
85
63
  Intent intent = new Intent(ACTION_BROADCAST);
86
64
  intent.putExtra("location", location);
87
- intent.putExtra("id", id);
65
+ intent.putExtra("id", callbackId);
88
66
  LocalBroadcastManager.getInstance(
89
67
  getApplicationContext()
90
68
  ).sendBroadcast(intent);
91
69
  };
92
70
 
93
- Watcher watcher = new Watcher();
94
- watcher.id = id;
95
- watcher.client = locationManager;
96
- watcher.distanceFilter = distanceFilter;
97
- watcher.locationCallback = listener;
98
- watcher.backgroundNotification = backgroundNotification;
99
- watchers.add(watcher);
100
-
101
- requestLocationUpdates(watcher);
71
+ try {
72
+ client.requestLocationUpdates(
73
+ LocationManager.GPS_PROVIDER,
74
+ 1000,
75
+ distanceFilter,
76
+ locationCallback
77
+ );
78
+ } catch (SecurityException ignore) {
79
+ // According to Android Studio, this method can throw a Security Exception if
80
+ // permissions are not yet granted. Rather than check the permissions, which is fiddly,
81
+ // we simply ignore the exception.
82
+ }
102
83
 
103
84
  // Promote the service to the foreground if necessary.
104
85
  // Ideally we would only call 'startForeground' if the service is not already
@@ -110,28 +91,109 @@ public class BackgroundGeolocationService extends Service {
110
91
  // This method has been known to fail due to weird
111
92
  // permission bugs, so we prevent any exceptions from
112
93
  // crashing the app. See issue #86.
113
- startForeground(NOTIFICATION_ID, backgroundNotification);
94
+ startForeground(
95
+ NOTIFICATION_ID,
96
+ createBackgroundNotification(notificationTitle, notificationMessage)
97
+ );
114
98
  } catch (Exception exception) {
115
99
  Logger.error("Failed to foreground service", exception);
116
100
  }
117
101
  }
118
102
 
119
- void removeWatcher(String id) {
120
- for (Watcher watcher : watchers) {
121
- if (watcher.id.equals(id)) {
122
- watcher.client.removeUpdates(watcher.locationCallback);
123
- watchers.remove(watcher);
124
- break;
125
- }
126
- }
127
- if (watchers.isEmpty()) {
128
- stopService();
103
+ String stop() {
104
+ client.removeUpdates(locationCallback);
105
+ stopForeground(true);
106
+ stopSelf();
107
+ return callbackId;
108
+ }
109
+ }
110
+
111
+ private Notification createBackgroundNotification(
112
+ String backgroundTitle,
113
+ String backgroundMessage
114
+ ) {
115
+ Notification.Builder builder = new Notification.Builder(
116
+ getApplicationContext()
117
+ )
118
+ .setContentTitle(backgroundTitle)
119
+ .setContentText(backgroundMessage)
120
+ .setOngoing(true)
121
+ .setPriority(Notification.PRIORITY_HIGH)
122
+ .setWhen(System.currentTimeMillis());
123
+
124
+ try {
125
+ String name = getAppString(
126
+ "capacitor_background_geolocation_notification_icon",
127
+ "mipmap/ic_launcher",
128
+ getApplicationContext()
129
+ );
130
+ String[] parts = name.split("/");
131
+ // It is actually necessary to set a valid icon for the notification to behave
132
+ // correctly when tapped. If there is no icon specified, tapping it will open the
133
+ // app's settings, rather than bringing the application to the foreground.
134
+ builder.setSmallIcon(
135
+ getAppResourceIdentifier(parts[1], parts[0], getApplicationContext())
136
+ );
137
+ } catch (Exception e) {
138
+ Logger.error("Could not set notification icon", e);
139
+ }
140
+
141
+ try {
142
+ String color = getAppString(
143
+ "capacitor_background_geolocation_notification_color",
144
+ null,
145
+ getApplicationContext()
146
+ );
147
+ if (color != null) {
148
+ builder.setColor(Color.parseColor(color));
129
149
  }
150
+ } catch (Exception e) {
151
+ Logger.error("Could not set notification color", e);
130
152
  }
131
153
 
132
- void stopService() {
133
- stopForeground(true);
134
- stopSelf();
154
+ Intent launchIntent = getApplicationContext()
155
+ .getPackageManager()
156
+ .getLaunchIntentForPackage(getApplicationContext().getPackageName());
157
+ if (launchIntent != null) {
158
+ launchIntent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
159
+ builder.setContentIntent(
160
+ PendingIntent.getActivity(
161
+ getApplicationContext(),
162
+ 0,
163
+ launchIntent,
164
+ PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE
165
+ )
166
+ );
135
167
  }
168
+
169
+ // Set the Channel ID for Android O.
170
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
171
+ builder.setChannelId(
172
+ BackgroundGeolocationService.class.getPackage().getName()
173
+ );
174
+ }
175
+
176
+ return builder.build();
177
+ }
178
+
179
+ // Gets the identifier of the app's resource by name, returning 0 if not found.
180
+ private static int getAppResourceIdentifier(
181
+ String name,
182
+ String defType,
183
+ Context context
184
+ ) {
185
+ return context
186
+ .getResources()
187
+ .getIdentifier(name, defType, context.getPackageName());
188
+ }
189
+
190
+ // Gets a string from the app's strings.xml file, resorting to a fallback if it is not defined.
191
+ public static String getAppString(
192
+ String name,
193
+ String fallback,
194
+ Context context
195
+ ) {
196
+ int id = getAppResourceIdentifier(name, "string", context);
197
+ return id == 0 ? fallback : context.getString(id);
136
198
  }
137
199
  }
package/dist/docs.json CHANGED
@@ -11,13 +11,13 @@
11
11
  ],
12
12
  "methods": [
13
13
  {
14
- "name": "addWatcher",
15
- "signature": "(options: WatcherOptions, callback: (position?: Location | undefined, error?: CallbackError | undefined) => void) => Promise<string>",
14
+ "name": "start",
15
+ "signature": "(options: StartOptions, callback: (position?: Location | undefined, error?: CallbackError | undefined) => void) => Promise<void>",
16
16
  "parameters": [
17
17
  {
18
18
  "name": "options",
19
19
  "docs": "The watcher configuration options",
20
- "type": "WatcherOptions"
20
+ "type": "StartOptions"
21
21
  },
22
22
  {
23
23
  "name": "callback",
@@ -25,7 +25,7 @@
25
25
  "type": "(position?: Location | undefined, error?: CallbackError | undefined) => void"
26
26
  }
27
27
  ],
28
- "returns": "Promise<string>",
28
+ "returns": "Promise<void>",
29
29
  "tags": [
30
30
  {
31
31
  "name": "param",
@@ -45,33 +45,23 @@
45
45
  },
46
46
  {
47
47
  "name": "example",
48
- "text": "const watcherId = await BackgroundGeolocation.addWatcher(\n {\n backgroundMessage: \"App is using your location in the background\",\n backgroundTitle: \"Location Service\",\n requestPermissions: true,\n stale: false,\n distanceFilter: 10\n },\n (location, error) => {\n if (error) {\n console.error('Location error:', error);\n return;\n }\n if (location) {\n console.log('New location:', location.latitude, location.longitude);\n }\n }\n);"
48
+ "text": "await BackgroundGeolocation.start(\n {\n backgroundMessage: \"App is using your location in the background\",\n backgroundTitle: \"Location Service\",\n requestPermissions: true,\n stale: false,\n distanceFilter: 10\n },\n (location, error) => {\n if (error) {\n console.error('Location error:', error);\n return;\n }\n if (location) {\n console.log('New location:', location.latitude, location.longitude);\n }\n }\n);"
49
49
  }
50
50
  ],
51
51
  "docs": "Adds a watcher for location updates.\nThe watcher will be invoked with the latest location whenever it is available.\nIf an error occurs, the callback will be invoked with the error.",
52
52
  "complexTypes": [
53
- "WatcherOptions",
53
+ "StartOptions",
54
54
  "Location",
55
55
  "CallbackError"
56
56
  ],
57
- "slug": "addwatcher"
57
+ "slug": "start"
58
58
  },
59
59
  {
60
- "name": "removeWatcher",
61
- "signature": "(options: { id: string; }) => Promise<void>",
62
- "parameters": [
63
- {
64
- "name": "options",
65
- "docs": "Object containing the watcher ID to remove",
66
- "type": "{ id: string; }"
67
- }
68
- ],
60
+ "name": "stop",
61
+ "signature": "() => Promise<void>",
62
+ "parameters": [],
69
63
  "returns": "Promise<void>",
70
64
  "tags": [
71
- {
72
- "name": "param",
73
- "text": "options Object containing the watcher ID to remove"
74
- },
75
65
  {
76
66
  "name": "returns",
77
67
  "text": "A promise that resolves when the watcher is successfully removed"
@@ -82,12 +72,12 @@
82
72
  },
83
73
  {
84
74
  "name": "example",
85
- "text": "await BackgroundGeolocation.removeWatcher({ id: watcherId });"
75
+ "text": "await BackgroundGeolocation.stop();"
86
76
  }
87
77
  ],
88
- "docs": "Removes a watcher by its unique identifier.\nStops location updates for the specified watcher.",
78
+ "docs": "Stops location updates.",
89
79
  "complexTypes": [],
90
- "slug": "removewatcher"
80
+ "slug": "stop"
91
81
  },
92
82
  {
93
83
  "name": "openSettings",
@@ -117,9 +107,9 @@
117
107
  },
118
108
  "interfaces": [
119
109
  {
120
- "name": "WatcherOptions",
121
- "slug": "watcheroptions",
122
- "docs": "The options for configuring a watcher that listens for location updates.",
110
+ "name": "StartOptions",
111
+ "slug": "startoptions",
112
+ "docs": "The options for configuring for location updates.",
123
113
  "tags": [
124
114
  {
125
115
  "text": "1.0.0",
@@ -1,9 +1,9 @@
1
1
  /**
2
- * The options for configuring a watcher that listens for location updates.
2
+ * The options for configuring for location updates.
3
3
  *
4
4
  * @since 1.0.0
5
5
  */
6
- export interface WatcherOptions {
6
+ export interface StartOptions {
7
7
  /**
8
8
  * If the "backgroundMessage" option is defined, the watcher will
9
9
  * provide location updates whether the app is in the background or the
@@ -180,7 +180,7 @@ export interface BackgroundGeolocationPlugin {
180
180
  *
181
181
  * @since 1.0.0
182
182
  * @example
183
- * const watcherId = await BackgroundGeolocation.addWatcher(
183
+ * await BackgroundGeolocation.start(
184
184
  * {
185
185
  * backgroundMessage: "App is using your location in the background",
186
186
  * backgroundTitle: "Location Service",
@@ -199,21 +199,17 @@ export interface BackgroundGeolocationPlugin {
199
199
  * }
200
200
  * );
201
201
  */
202
- addWatcher(options: WatcherOptions, callback: (position?: Location, error?: CallbackError) => void): Promise<string>;
202
+ start(options: StartOptions, callback: (position?: Location, error?: CallbackError) => void): Promise<void>;
203
203
  /**
204
- * Removes a watcher by its unique identifier.
205
- * Stops location updates for the specified watcher.
204
+ * Stops location updates.
206
205
  *
207
- * @param options Object containing the watcher ID to remove
208
206
  * @returns A promise that resolves when the watcher is successfully removed
209
207
  *
210
208
  * @since 1.0.0
211
209
  * @example
212
- * await BackgroundGeolocation.removeWatcher({ id: watcherId });
210
+ * await BackgroundGeolocation.stop();
213
211
  */
214
- removeWatcher(options: {
215
- id: string;
216
- }): Promise<void>;
212
+ stop(): Promise<void>;
217
213
  /**
218
214
  * Opens the device's location settings page.
219
215
  * Useful for directing users to enable location services or adjust permissions.
@@ -1 +1 @@
1
- {"version":3,"file":"definitions.js","sourceRoot":"","sources":["../../src/definitions.ts"],"names":[],"mappings":"","sourcesContent":["/**\n * The options for configuring a watcher that listens for location updates.\n *\n * @since 1.0.0\n */\nexport interface WatcherOptions {\n /**\n * If the \"backgroundMessage\" option is defined, the watcher will\n * provide location updates whether the app is in the background or the\n * foreground. If it is not defined, location updates are only\n * guaranteed in the foreground. This is true on both platforms.\n *\n * On Android, a notification must be shown to continue receiving\n * location updates in the background. This option specifies the text of\n * that notification.\n *\n * @since 1.0.0\n * @example \"Getting your location to provide better service\"\n */\n backgroundMessage?: string;\n /**\n * The title of the notification mentioned above.\n *\n * @since 1.0.0\n * @default \"Using your location\"\n * @example \"Location Service\"\n */\n backgroundTitle?: string;\n /**\n * Whether permissions should be requested from the user automatically,\n * if they are not already granted.\n *\n * @since 1.0.0\n * @default true\n * @example\n * // Auto-request permissions\n * requestPermissions: true\n *\n * // Don't auto-request, handle manually\n * requestPermissions: false\n */\n requestPermissions?: boolean;\n /**\n * If \"true\", stale locations may be delivered while the device\n * obtains a GPS fix. You are responsible for checking the \"time\"\n * property. If \"false\", locations are guaranteed to be up to date.\n *\n * @since 1.0.0\n * @default false\n * @example\n * // Allow stale locations for faster initial response\n * stale: true\n *\n * // Only fresh locations\n * stale: false\n */\n stale?: boolean;\n /**\n * The distance in meters that the device must move before a new location update is triggered.\n * This is used to filter out small movements and reduce the number of updates.\n *\n * @since 1.0.0\n * @default 0\n * @example\n * // Update every 10 meters\n * distanceFilter: 10\n *\n * // Update on any movement\n * distanceFilter: 0\n */\n distanceFilter?: number;\n}\n\n/**\n * Represents a geographical location with various attributes.\n * Contains all the standard location properties returned by GPS/network providers.\n *\n * @since 1.0.0\n */\nexport interface Location {\n /**\n * Latitude in degrees.\n * Range: -90.0 to +90.0\n *\n * @since 1.0.0\n * @example 40.7128\n */\n latitude: number;\n /**\n * Longitude in degrees.\n * Range: -180.0 to +180.0\n *\n * @since 1.0.0\n * @example -74.0060\n */\n longitude: number;\n /**\n * Radius of horizontal uncertainty in metres, with 68% confidence.\n * Lower values indicate more accurate location.\n *\n * @since 1.0.0\n * @example 5.0\n */\n accuracy: number;\n /**\n * Metres above sea level (or null if not available).\n *\n * @since 1.0.0\n * @example 10.5\n */\n altitude: number | null;\n /**\n * Vertical uncertainty in metres, with 68% confidence (or null if not available).\n *\n * @since 1.0.0\n * @example 3.0\n */\n altitudeAccuracy: number | null;\n /**\n * `true` if the location was simulated by software, rather than GPS.\n * Useful for detecting mock locations in development or testing.\n *\n * @since 1.0.0\n * @example false\n */\n simulated: boolean;\n /**\n * Deviation from true north in degrees (or null if not available).\n * Range: 0.0 to 360.0\n *\n * @since 1.0.0\n * @example 45.5\n */\n bearing: number | null;\n /**\n * Speed in metres per second (or null if not available).\n *\n * @since 1.0.0\n * @example 2.5\n */\n speed: number | null;\n /**\n * Time the location was produced, in milliseconds since the unix epoch.\n * Use this to check if a location is stale when using stale: true.\n *\n * @since 1.0.0\n * @example 1640995200000\n */\n time: number | null;\n}\n\n/**\n * Error object that may be passed to the location watcher callback.\n * Extends the standard Error with optional error codes.\n *\n * @since 1.0.0\n */\nexport interface CallbackError extends Error {\n /**\n * Optional error code for more specific error handling.\n *\n * @since 1.0.0\n * @example \"PERMISSION_DENIED\"\n */\n code?: string;\n}\n\n/**\n * Main plugin interface for background geolocation functionality.\n * Provides methods to manage location watchers and access device settings.\n *\n * @since 1.0.0\n */\nexport interface BackgroundGeolocationPlugin {\n /**\n * Adds a watcher for location updates.\n * The watcher will be invoked with the latest location whenever it is available.\n * If an error occurs, the callback will be invoked with the error.\n *\n * @param options The watcher configuration options\n * @param callback The callback function invoked when a new location is available or an error occurs\n * @returns A promise that resolves to a unique identifier for the watcher ID\n *\n * @since 1.0.0\n * @example\n * const watcherId = await BackgroundGeolocation.addWatcher(\n * {\n * backgroundMessage: \"App is using your location in the background\",\n * backgroundTitle: \"Location Service\",\n * requestPermissions: true,\n * stale: false,\n * distanceFilter: 10\n * },\n * (location, error) => {\n * if (error) {\n * console.error('Location error:', error);\n * return;\n * }\n * if (location) {\n * console.log('New location:', location.latitude, location.longitude);\n * }\n * }\n * );\n */\n addWatcher(\n options: WatcherOptions,\n callback: (position?: Location, error?: CallbackError) => void,\n ): Promise<string>;\n\n /**\n * Removes a watcher by its unique identifier.\n * Stops location updates for the specified watcher.\n *\n * @param options Object containing the watcher ID to remove\n * @returns A promise that resolves when the watcher is successfully removed\n *\n * @since 1.0.0\n * @example\n * await BackgroundGeolocation.removeWatcher({ id: watcherId });\n */\n removeWatcher(options: { id: string }): Promise<void>;\n\n /**\n * Opens the device's location settings page.\n * Useful for directing users to enable location services or adjust permissions.\n *\n * @returns A promise that resolves when the settings page is opened\n *\n * @since 1.0.0\n * @example\n * // Direct user to location settings\n * await BackgroundGeolocation.openSettings();\n */\n openSettings(): Promise<void>;\n}\n"]}
1
+ {"version":3,"file":"definitions.js","sourceRoot":"","sources":["../../src/definitions.ts"],"names":[],"mappings":"","sourcesContent":["/**\n * The options for configuring for location updates.\n *\n * @since 1.0.0\n */\nexport interface StartOptions {\n /**\n * If the \"backgroundMessage\" option is defined, the watcher will\n * provide location updates whether the app is in the background or the\n * foreground. If it is not defined, location updates are only\n * guaranteed in the foreground. This is true on both platforms.\n *\n * On Android, a notification must be shown to continue receiving\n * location updates in the background. This option specifies the text of\n * that notification.\n *\n * @since 1.0.0\n * @example \"Getting your location to provide better service\"\n */\n backgroundMessage?: string;\n /**\n * The title of the notification mentioned above.\n *\n * @since 1.0.0\n * @default \"Using your location\"\n * @example \"Location Service\"\n */\n backgroundTitle?: string;\n /**\n * Whether permissions should be requested from the user automatically,\n * if they are not already granted.\n *\n * @since 1.0.0\n * @default true\n * @example\n * // Auto-request permissions\n * requestPermissions: true\n *\n * // Don't auto-request, handle manually\n * requestPermissions: false\n */\n requestPermissions?: boolean;\n /**\n * If \"true\", stale locations may be delivered while the device\n * obtains a GPS fix. You are responsible for checking the \"time\"\n * property. If \"false\", locations are guaranteed to be up to date.\n *\n * @since 1.0.0\n * @default false\n * @example\n * // Allow stale locations for faster initial response\n * stale: true\n *\n * // Only fresh locations\n * stale: false\n */\n stale?: boolean;\n /**\n * The distance in meters that the device must move before a new location update is triggered.\n * This is used to filter out small movements and reduce the number of updates.\n *\n * @since 1.0.0\n * @default 0\n * @example\n * // Update every 10 meters\n * distanceFilter: 10\n *\n * // Update on any movement\n * distanceFilter: 0\n */\n distanceFilter?: number;\n}\n\n/**\n * Represents a geographical location with various attributes.\n * Contains all the standard location properties returned by GPS/network providers.\n *\n * @since 1.0.0\n */\nexport interface Location {\n /**\n * Latitude in degrees.\n * Range: -90.0 to +90.0\n *\n * @since 1.0.0\n * @example 40.7128\n */\n latitude: number;\n /**\n * Longitude in degrees.\n * Range: -180.0 to +180.0\n *\n * @since 1.0.0\n * @example -74.0060\n */\n longitude: number;\n /**\n * Radius of horizontal uncertainty in metres, with 68% confidence.\n * Lower values indicate more accurate location.\n *\n * @since 1.0.0\n * @example 5.0\n */\n accuracy: number;\n /**\n * Metres above sea level (or null if not available).\n *\n * @since 1.0.0\n * @example 10.5\n */\n altitude: number | null;\n /**\n * Vertical uncertainty in metres, with 68% confidence (or null if not available).\n *\n * @since 1.0.0\n * @example 3.0\n */\n altitudeAccuracy: number | null;\n /**\n * `true` if the location was simulated by software, rather than GPS.\n * Useful for detecting mock locations in development or testing.\n *\n * @since 1.0.0\n * @example false\n */\n simulated: boolean;\n /**\n * Deviation from true north in degrees (or null if not available).\n * Range: 0.0 to 360.0\n *\n * @since 1.0.0\n * @example 45.5\n */\n bearing: number | null;\n /**\n * Speed in metres per second (or null if not available).\n *\n * @since 1.0.0\n * @example 2.5\n */\n speed: number | null;\n /**\n * Time the location was produced, in milliseconds since the unix epoch.\n * Use this to check if a location is stale when using stale: true.\n *\n * @since 1.0.0\n * @example 1640995200000\n */\n time: number | null;\n}\n\n/**\n * Error object that may be passed to the location watcher callback.\n * Extends the standard Error with optional error codes.\n *\n * @since 1.0.0\n */\nexport interface CallbackError extends Error {\n /**\n * Optional error code for more specific error handling.\n *\n * @since 1.0.0\n * @example \"PERMISSION_DENIED\"\n */\n code?: string;\n}\n\n/**\n * Main plugin interface for background geolocation functionality.\n * Provides methods to manage location watchers and access device settings.\n *\n * @since 1.0.0\n */\nexport interface BackgroundGeolocationPlugin {\n /**\n * Adds a watcher for location updates.\n * The watcher will be invoked with the latest location whenever it is available.\n * If an error occurs, the callback will be invoked with the error.\n *\n * @param options The watcher configuration options\n * @param callback The callback function invoked when a new location is available or an error occurs\n * @returns A promise that resolves to a unique identifier for the watcher ID\n *\n * @since 1.0.0\n * @example\n * await BackgroundGeolocation.start(\n * {\n * backgroundMessage: \"App is using your location in the background\",\n * backgroundTitle: \"Location Service\",\n * requestPermissions: true,\n * stale: false,\n * distanceFilter: 10\n * },\n * (location, error) => {\n * if (error) {\n * console.error('Location error:', error);\n * return;\n * }\n * if (location) {\n * console.log('New location:', location.latitude, location.longitude);\n * }\n * }\n * );\n */\n start(\n options: StartOptions,\n callback: (position?: Location, error?: CallbackError) => void,\n ): Promise<void>;\n\n /**\n * Stops location updates.\n *\n * @returns A promise that resolves when the watcher is successfully removed\n *\n * @since 1.0.0\n * @example\n * await BackgroundGeolocation.stop();\n */\n stop(): Promise<void>;\n\n /**\n * Opens the device's location settings page.\n * Useful for directing users to enable location services or adjust permissions.\n *\n * @returns A promise that resolves when the settings page is opened\n *\n * @since 1.0.0\n * @example\n * // Direct user to location settings\n * await BackgroundGeolocation.openSettings();\n */\n openSettings(): Promise<void>;\n}\n"]}
package/dist/esm/web.d.ts CHANGED
@@ -1,11 +1,8 @@
1
1
  import { WebPlugin } from "@capacitor/core";
2
- import type { BackgroundGeolocationPlugin, WatcherOptions, Location, CallbackError } from "./definitions";
2
+ import type { BackgroundGeolocationPlugin, StartOptions, Location, CallbackError } from "./definitions";
3
3
  export declare class BackgroundGeolocationWeb extends WebPlugin implements BackgroundGeolocationPlugin {
4
- private watchers;
5
- private watcherCounter;
6
- addWatcher(options: WatcherOptions, callback: (position?: Location, error?: CallbackError) => void): Promise<string>;
7
- removeWatcher(options: {
8
- id: string;
9
- }): Promise<void>;
4
+ private watchId;
5
+ start(options: StartOptions, callback: (position?: Location, error?: CallbackError) => void): Promise<void>;
6
+ stop(): Promise<void>;
10
7
  openSettings(): Promise<void>;
11
8
  }
package/dist/esm/web.js CHANGED
@@ -1,21 +1,23 @@
1
1
  import { WebPlugin } from "@capacitor/core";
2
2
  export class BackgroundGeolocationWeb extends WebPlugin {
3
- constructor() {
4
- super(...arguments);
5
- this.watchers = new Map();
6
- this.watcherCounter = 0;
7
- }
8
- async addWatcher(options, callback) {
9
- const watcherId = `watcher_${++this.watcherCounter}`;
3
+ async start(options, callback) {
10
4
  if (!navigator.geolocation) {
11
5
  callback(undefined, {
12
6
  name: "GeolocationError",
13
7
  message: "Geolocation is not supported by this browser",
14
8
  code: "NOT_SUPPORTED",
15
9
  });
16
- return watcherId;
10
+ return;
11
+ }
12
+ if (this.watchId) {
13
+ callback(undefined, {
14
+ name: "GeolocationError",
15
+ message: "Geolocation already started",
16
+ code: "ALREADY_STARTED",
17
+ });
18
+ return;
17
19
  }
18
- const watchId = navigator.geolocation.watchPosition((position) => {
20
+ this.watchId = navigator.geolocation.watchPosition((position) => {
19
21
  const location = {
20
22
  latitude: position.coords.latitude,
21
23
  longitude: position.coords.longitude,
@@ -40,14 +42,11 @@ export class BackgroundGeolocationWeb extends WebPlugin {
40
42
  timeout: 10000,
41
43
  maximumAge: options.stale ? 300000 : 0,
42
44
  });
43
- this.watchers.set(watcherId, { watchId, callback });
44
- return watcherId;
45
45
  }
46
- async removeWatcher(options) {
47
- const watcher = this.watchers.get(options.id);
48
- if (watcher) {
49
- navigator.geolocation.clearWatch(watcher.watchId);
50
- this.watchers.delete(options.id);
46
+ async stop() {
47
+ if (this.watchId) {
48
+ navigator.geolocation.clearWatch(this.watchId);
49
+ delete this.watchId;
51
50
  }
52
51
  }
53
52
  async openSettings() {
@@ -1 +1 @@
1
- {"version":3,"file":"web.js","sourceRoot":"","sources":["../../src/web.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAS5C,MAAM,OAAO,wBACX,SAAQ,SAAS;IADnB;;QAIU,aAAQ,GAAG,IAAI,GAAG,EAMvB,CAAC;QACI,mBAAc,GAAG,CAAC,CAAC;IA+D7B,CAAC;IA7DC,KAAK,CAAC,UAAU,CACd,OAAuB,EACvB,QAA8D;QAE9D,MAAM,SAAS,GAAG,WAAW,EAAE,IAAI,CAAC,cAAc,EAAE,CAAC;QAErD,IAAI,CAAC,SAAS,CAAC,WAAW,EAAE,CAAC;YAC3B,QAAQ,CAAC,SAAS,EAAE;gBAClB,IAAI,EAAE,kBAAkB;gBACxB,OAAO,EAAE,8CAA8C;gBACvD,IAAI,EAAE,eAAe;aACtB,CAAC,CAAC;YACH,OAAO,SAAS,CAAC;QACnB,CAAC;QAED,MAAM,OAAO,GAAG,SAAS,CAAC,WAAW,CAAC,aAAa,CACjD,CAAC,QAAQ,EAAE,EAAE;YACX,MAAM,QAAQ,GAAa;gBACzB,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,QAAQ;gBAClC,SAAS,EAAE,QAAQ,CAAC,MAAM,CAAC,SAAS;gBACpC,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,QAAQ;gBAClC,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,QAAQ;gBAClC,gBAAgB,EAAE,QAAQ,CAAC,MAAM,CAAC,gBAAgB;gBAClD,SAAS,EAAE,KAAK;gBAChB,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,OAAO;gBAChC,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,KAAK;gBAC5B,IAAI,EAAE,QAAQ,CAAC,SAAS;aACzB,CAAC;YACF,QAAQ,CAAC,QAAQ,CAAC,CAAC;QACrB,CAAC,EACD,CAAC,KAAK,EAAE,EAAE;YACR,MAAM,aAAa,GAAkB;gBACnC,IAAI,EAAE,kBAAkB;gBACxB,OAAO,EAAE,KAAK,CAAC,OAAO;gBACtB,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,QAAQ,EAAE;aAC5B,CAAC;YACF,QAAQ,CAAC,SAAS,EAAE,aAAa,CAAC,CAAC;QACrC,CAAC,EACD;YACE,kBAAkB,EAAE,IAAI;YACxB,OAAO,EAAE,KAAK;YACd,UAAU,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;SACvC,CACF,CAAC;QAEF,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,EAAE,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,CAAC;QACpD,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,KAAK,CAAC,aAAa,CAAC,OAAuB;QACzC,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QAC9C,IAAI,OAAO,EAAE,CAAC;YACZ,SAAS,CAAC,WAAW,CAAC,UAAU,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;YAClD,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QACnC,CAAC;IACH,CAAC;IAED,KAAK,CAAC,YAAY;QAChB,OAAO,CAAC,GAAG,CAAC,8DAA8D,CAAC,CAAC;QAC5E,MAAM,CAAC,KAAK,CAAC,6DAA6D,CAAC,CAAC;IAC9E,CAAC;CACF","sourcesContent":["import { WebPlugin } from \"@capacitor/core\";\n\nimport type {\n BackgroundGeolocationPlugin,\n WatcherOptions,\n Location,\n CallbackError,\n} from \"./definitions\";\n\nexport class BackgroundGeolocationWeb\n extends WebPlugin\n implements BackgroundGeolocationPlugin\n{\n private watchers = new Map<\n string,\n {\n watchId: number;\n callback: (position?: Location, error?: CallbackError) => void;\n }\n >();\n private watcherCounter = 0;\n\n async addWatcher(\n options: WatcherOptions,\n callback: (position?: Location, error?: CallbackError) => void,\n ): Promise<string> {\n const watcherId = `watcher_${++this.watcherCounter}`;\n\n if (!navigator.geolocation) {\n callback(undefined, {\n name: \"GeolocationError\",\n message: \"Geolocation is not supported by this browser\",\n code: \"NOT_SUPPORTED\",\n });\n return watcherId;\n }\n\n const watchId = navigator.geolocation.watchPosition(\n (position) => {\n const location: Location = {\n latitude: position.coords.latitude,\n longitude: position.coords.longitude,\n accuracy: position.coords.accuracy,\n altitude: position.coords.altitude,\n altitudeAccuracy: position.coords.altitudeAccuracy,\n simulated: false,\n bearing: position.coords.heading,\n speed: position.coords.speed,\n time: position.timestamp,\n };\n callback(location);\n },\n (error) => {\n const callbackError: CallbackError = {\n name: \"GeolocationError\",\n message: error.message,\n code: error.code.toString(),\n };\n callback(undefined, callbackError);\n },\n {\n enableHighAccuracy: true,\n timeout: 10000,\n maximumAge: options.stale ? 300000 : 0,\n },\n );\n\n this.watchers.set(watcherId, { watchId, callback });\n return watcherId;\n }\n\n async removeWatcher(options: { id: string }): Promise<void> {\n const watcher = this.watchers.get(options.id);\n if (watcher) {\n navigator.geolocation.clearWatch(watcher.watchId);\n this.watchers.delete(options.id);\n }\n }\n\n async openSettings(): Promise<void> {\n console.log(\"openSettings: Web implementation cannot open native settings\");\n window.alert(\"Please enable location permissions in your browser settings\");\n }\n}\n"]}
1
+ {"version":3,"file":"web.js","sourceRoot":"","sources":["../../src/web.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAS5C,MAAM,OAAO,wBACX,SAAQ,SAAS;IAKjB,KAAK,CAAC,KAAK,CACT,OAAqB,EACrB,QAA8D;QAE9D,IAAI,CAAC,SAAS,CAAC,WAAW,EAAE,CAAC;YAC3B,QAAQ,CAAC,SAAS,EAAE;gBAClB,IAAI,EAAE,kBAAkB;gBACxB,OAAO,EAAE,8CAA8C;gBACvD,IAAI,EAAE,eAAe;aACtB,CAAC,CAAC;YACH,OAAO;QACT,CAAC;QAED,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACjB,QAAQ,CAAC,SAAS,EAAE;gBAClB,IAAI,EAAE,kBAAkB;gBACxB,OAAO,EAAE,6BAA6B;gBACtC,IAAI,EAAE,iBAAiB;aACxB,CAAC,CAAC;YACH,OAAO;QACT,CAAC;QAED,IAAI,CAAC,OAAO,GAAG,SAAS,CAAC,WAAW,CAAC,aAAa,CAChD,CAAC,QAAQ,EAAE,EAAE;YACX,MAAM,QAAQ,GAAa;gBACzB,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,QAAQ;gBAClC,SAAS,EAAE,QAAQ,CAAC,MAAM,CAAC,SAAS;gBACpC,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,QAAQ;gBAClC,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,QAAQ;gBAClC,gBAAgB,EAAE,QAAQ,CAAC,MAAM,CAAC,gBAAgB;gBAClD,SAAS,EAAE,KAAK;gBAChB,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,OAAO;gBAChC,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,KAAK;gBAC5B,IAAI,EAAE,QAAQ,CAAC,SAAS;aACzB,CAAC;YACF,QAAQ,CAAC,QAAQ,CAAC,CAAC;QACrB,CAAC,EACD,CAAC,KAAK,EAAE,EAAE;YACR,MAAM,aAAa,GAAkB;gBACnC,IAAI,EAAE,kBAAkB;gBACxB,OAAO,EAAE,KAAK,CAAC,OAAO;gBACtB,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,QAAQ,EAAE;aAC5B,CAAC;YACF,QAAQ,CAAC,SAAS,EAAE,aAAa,CAAC,CAAC;QACrC,CAAC,EACD;YACE,kBAAkB,EAAE,IAAI;YACxB,OAAO,EAAE,KAAK;YACd,UAAU,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;SACvC,CACF,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,IAAI;QACR,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACjB,SAAS,CAAC,WAAW,CAAC,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAC/C,OAAO,IAAI,CAAC,OAAO,CAAC;QACtB,CAAC;IACH,CAAC;IAED,KAAK,CAAC,YAAY;QAChB,OAAO,CAAC,GAAG,CAAC,8DAA8D,CAAC,CAAC;QAC5E,MAAM,CAAC,KAAK,CAAC,6DAA6D,CAAC,CAAC;IAC9E,CAAC;CACF","sourcesContent":["import { WebPlugin } from \"@capacitor/core\";\n\nimport type {\n BackgroundGeolocationPlugin,\n StartOptions,\n Location,\n CallbackError,\n} from \"./definitions\";\n\nexport class BackgroundGeolocationWeb\n extends WebPlugin\n implements BackgroundGeolocationPlugin\n{\n private watchId: number | undefined;\n\n async start(\n options: StartOptions,\n callback: (position?: Location, error?: CallbackError) => void,\n ): Promise<void> {\n if (!navigator.geolocation) {\n callback(undefined, {\n name: \"GeolocationError\",\n message: \"Geolocation is not supported by this browser\",\n code: \"NOT_SUPPORTED\",\n });\n return;\n }\n\n if (this.watchId) {\n callback(undefined, {\n name: \"GeolocationError\",\n message: \"Geolocation already started\",\n code: \"ALREADY_STARTED\",\n });\n return;\n }\n\n this.watchId = navigator.geolocation.watchPosition(\n (position) => {\n const location: Location = {\n latitude: position.coords.latitude,\n longitude: position.coords.longitude,\n accuracy: position.coords.accuracy,\n altitude: position.coords.altitude,\n altitudeAccuracy: position.coords.altitudeAccuracy,\n simulated: false,\n bearing: position.coords.heading,\n speed: position.coords.speed,\n time: position.timestamp,\n };\n callback(location);\n },\n (error) => {\n const callbackError: CallbackError = {\n name: \"GeolocationError\",\n message: error.message,\n code: error.code.toString(),\n };\n callback(undefined, callbackError);\n },\n {\n enableHighAccuracy: true,\n timeout: 10000,\n maximumAge: options.stale ? 300000 : 0,\n },\n );\n }\n\n async stop(): Promise<void> {\n if (this.watchId) {\n navigator.geolocation.clearWatch(this.watchId);\n delete this.watchId;\n }\n }\n\n async openSettings(): Promise<void> {\n console.log(\"openSettings: Web implementation cannot open native settings\");\n window.alert(\"Please enable location permissions in your browser settings\");\n }\n}\n"]}
@@ -7,22 +7,24 @@ const BackgroundGeolocation = core.registerPlugin("BackgroundGeolocation", {
7
7
  });
8
8
 
9
9
  class BackgroundGeolocationWeb extends core.WebPlugin {
10
- constructor() {
11
- super(...arguments);
12
- this.watchers = new Map();
13
- this.watcherCounter = 0;
14
- }
15
- async addWatcher(options, callback) {
16
- const watcherId = `watcher_${++this.watcherCounter}`;
10
+ async start(options, callback) {
17
11
  if (!navigator.geolocation) {
18
12
  callback(undefined, {
19
13
  name: "GeolocationError",
20
14
  message: "Geolocation is not supported by this browser",
21
15
  code: "NOT_SUPPORTED",
22
16
  });
23
- return watcherId;
17
+ return;
18
+ }
19
+ if (this.watchId) {
20
+ callback(undefined, {
21
+ name: "GeolocationError",
22
+ message: "Geolocation already started",
23
+ code: "ALREADY_STARTED",
24
+ });
25
+ return;
24
26
  }
25
- const watchId = navigator.geolocation.watchPosition((position) => {
27
+ this.watchId = navigator.geolocation.watchPosition((position) => {
26
28
  const location = {
27
29
  latitude: position.coords.latitude,
28
30
  longitude: position.coords.longitude,
@@ -47,14 +49,11 @@ class BackgroundGeolocationWeb extends core.WebPlugin {
47
49
  timeout: 10000,
48
50
  maximumAge: options.stale ? 300000 : 0,
49
51
  });
50
- this.watchers.set(watcherId, { watchId, callback });
51
- return watcherId;
52
52
  }
53
- async removeWatcher(options) {
54
- const watcher = this.watchers.get(options.id);
55
- if (watcher) {
56
- navigator.geolocation.clearWatch(watcher.watchId);
57
- this.watchers.delete(options.id);
53
+ async stop() {
54
+ if (this.watchId) {
55
+ navigator.geolocation.clearWatch(this.watchId);
56
+ delete this.watchId;
58
57
  }
59
58
  }
60
59
  async openSettings() {
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.cjs.js","sources":["esm/index.js","esm/web.js"],"sourcesContent":["import { registerPlugin } from \"@capacitor/core\";\nconst BackgroundGeolocation = registerPlugin(\"BackgroundGeolocation\", {\n web: () => import(\"./web\").then((m) => new m.BackgroundGeolocationWeb()),\n});\nexport * from \"./definitions\";\nexport { BackgroundGeolocation };\n//# sourceMappingURL=index.js.map","import { WebPlugin } from \"@capacitor/core\";\nexport class BackgroundGeolocationWeb extends WebPlugin {\n constructor() {\n super(...arguments);\n this.watchers = new Map();\n this.watcherCounter = 0;\n }\n async addWatcher(options, callback) {\n const watcherId = `watcher_${++this.watcherCounter}`;\n if (!navigator.geolocation) {\n callback(undefined, {\n name: \"GeolocationError\",\n message: \"Geolocation is not supported by this browser\",\n code: \"NOT_SUPPORTED\",\n });\n return watcherId;\n }\n const watchId = navigator.geolocation.watchPosition((position) => {\n const location = {\n latitude: position.coords.latitude,\n longitude: position.coords.longitude,\n accuracy: position.coords.accuracy,\n altitude: position.coords.altitude,\n altitudeAccuracy: position.coords.altitudeAccuracy,\n simulated: false,\n bearing: position.coords.heading,\n speed: position.coords.speed,\n time: position.timestamp,\n };\n callback(location);\n }, (error) => {\n const callbackError = {\n name: \"GeolocationError\",\n message: error.message,\n code: error.code.toString(),\n };\n callback(undefined, callbackError);\n }, {\n enableHighAccuracy: true,\n timeout: 10000,\n maximumAge: options.stale ? 300000 : 0,\n });\n this.watchers.set(watcherId, { watchId, callback });\n return watcherId;\n }\n async removeWatcher(options) {\n const watcher = this.watchers.get(options.id);\n if (watcher) {\n navigator.geolocation.clearWatch(watcher.watchId);\n this.watchers.delete(options.id);\n }\n }\n async openSettings() {\n console.log(\"openSettings: Web implementation cannot open native settings\");\n window.alert(\"Please enable location permissions in your browser settings\");\n }\n}\n//# sourceMappingURL=web.js.map"],"names":["registerPlugin","WebPlugin"],"mappings":"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"}
1
+ {"version":3,"file":"plugin.cjs.js","sources":["esm/index.js","esm/web.js"],"sourcesContent":["import { registerPlugin } from \"@capacitor/core\";\nconst BackgroundGeolocation = registerPlugin(\"BackgroundGeolocation\", {\n web: () => import(\"./web\").then((m) => new m.BackgroundGeolocationWeb()),\n});\nexport * from \"./definitions\";\nexport { BackgroundGeolocation };\n//# sourceMappingURL=index.js.map","import { WebPlugin } from \"@capacitor/core\";\nexport class BackgroundGeolocationWeb extends WebPlugin {\n async start(options, callback) {\n if (!navigator.geolocation) {\n callback(undefined, {\n name: \"GeolocationError\",\n message: \"Geolocation is not supported by this browser\",\n code: \"NOT_SUPPORTED\",\n });\n return;\n }\n if (this.watchId) {\n callback(undefined, {\n name: \"GeolocationError\",\n message: \"Geolocation already started\",\n code: \"ALREADY_STARTED\",\n });\n return;\n }\n this.watchId = navigator.geolocation.watchPosition((position) => {\n const location = {\n latitude: position.coords.latitude,\n longitude: position.coords.longitude,\n accuracy: position.coords.accuracy,\n altitude: position.coords.altitude,\n altitudeAccuracy: position.coords.altitudeAccuracy,\n simulated: false,\n bearing: position.coords.heading,\n speed: position.coords.speed,\n time: position.timestamp,\n };\n callback(location);\n }, (error) => {\n const callbackError = {\n name: \"GeolocationError\",\n message: error.message,\n code: error.code.toString(),\n };\n callback(undefined, callbackError);\n }, {\n enableHighAccuracy: true,\n timeout: 10000,\n maximumAge: options.stale ? 300000 : 0,\n });\n }\n async stop() {\n if (this.watchId) {\n navigator.geolocation.clearWatch(this.watchId);\n delete this.watchId;\n }\n }\n async openSettings() {\n console.log(\"openSettings: Web implementation cannot open native settings\");\n window.alert(\"Please enable location permissions in your browser settings\");\n }\n}\n//# sourceMappingURL=web.js.map"],"names":["registerPlugin","WebPlugin"],"mappings":";;;;AACK,MAAC,qBAAqB,GAAGA,mBAAc,CAAC,uBAAuB,EAAE;AACtE,IAAI,GAAG,EAAE,MAAM,mDAAe,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,wBAAwB,EAAE,CAAC;AAC5E,CAAC;;ACFM,MAAM,wBAAwB,SAASC,cAAS,CAAC;AACxD,IAAI,MAAM,KAAK,CAAC,OAAO,EAAE,QAAQ,EAAE;AACnC,QAAQ,IAAI,CAAC,SAAS,CAAC,WAAW,EAAE;AACpC,YAAY,QAAQ,CAAC,SAAS,EAAE;AAChC,gBAAgB,IAAI,EAAE,kBAAkB;AACxC,gBAAgB,OAAO,EAAE,8CAA8C;AACvE,gBAAgB,IAAI,EAAE,eAAe;AACrC,aAAa,CAAC;AACd,YAAY;AACZ,QAAQ;AACR,QAAQ,IAAI,IAAI,CAAC,OAAO,EAAE;AAC1B,YAAY,QAAQ,CAAC,SAAS,EAAE;AAChC,gBAAgB,IAAI,EAAE,kBAAkB;AACxC,gBAAgB,OAAO,EAAE,6BAA6B;AACtD,gBAAgB,IAAI,EAAE,iBAAiB;AACvC,aAAa,CAAC;AACd,YAAY;AACZ,QAAQ;AACR,QAAQ,IAAI,CAAC,OAAO,GAAG,SAAS,CAAC,WAAW,CAAC,aAAa,CAAC,CAAC,QAAQ,KAAK;AACzE,YAAY,MAAM,QAAQ,GAAG;AAC7B,gBAAgB,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,QAAQ;AAClD,gBAAgB,SAAS,EAAE,QAAQ,CAAC,MAAM,CAAC,SAAS;AACpD,gBAAgB,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,QAAQ;AAClD,gBAAgB,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,QAAQ;AAClD,gBAAgB,gBAAgB,EAAE,QAAQ,CAAC,MAAM,CAAC,gBAAgB;AAClE,gBAAgB,SAAS,EAAE,KAAK;AAChC,gBAAgB,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,OAAO;AAChD,gBAAgB,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,KAAK;AAC5C,gBAAgB,IAAI,EAAE,QAAQ,CAAC,SAAS;AACxC,aAAa;AACb,YAAY,QAAQ,CAAC,QAAQ,CAAC;AAC9B,QAAQ,CAAC,EAAE,CAAC,KAAK,KAAK;AACtB,YAAY,MAAM,aAAa,GAAG;AAClC,gBAAgB,IAAI,EAAE,kBAAkB;AACxC,gBAAgB,OAAO,EAAE,KAAK,CAAC,OAAO;AACtC,gBAAgB,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,QAAQ,EAAE;AAC3C,aAAa;AACb,YAAY,QAAQ,CAAC,SAAS,EAAE,aAAa,CAAC;AAC9C,QAAQ,CAAC,EAAE;AACX,YAAY,kBAAkB,EAAE,IAAI;AACpC,YAAY,OAAO,EAAE,KAAK;AAC1B,YAAY,UAAU,EAAE,OAAO,CAAC,KAAK,GAAG,MAAM,GAAG,CAAC;AAClD,SAAS,CAAC;AACV,IAAI;AACJ,IAAI,MAAM,IAAI,GAAG;AACjB,QAAQ,IAAI,IAAI,CAAC,OAAO,EAAE;AAC1B,YAAY,SAAS,CAAC,WAAW,CAAC,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC;AAC1D,YAAY,OAAO,IAAI,CAAC,OAAO;AAC/B,QAAQ;AACR,IAAI;AACJ,IAAI,MAAM,YAAY,GAAG;AACzB,QAAQ,OAAO,CAAC,GAAG,CAAC,8DAA8D,CAAC;AACnF,QAAQ,MAAM,CAAC,KAAK,CAAC,6DAA6D,CAAC;AACnF,IAAI;AACJ;;;;;;;;;"}
package/dist/plugin.js CHANGED
@@ -6,22 +6,24 @@ var capacitorBackgroundGeolocation = (function (exports, core) {
6
6
  });
7
7
 
8
8
  class BackgroundGeolocationWeb extends core.WebPlugin {
9
- constructor() {
10
- super(...arguments);
11
- this.watchers = new Map();
12
- this.watcherCounter = 0;
13
- }
14
- async addWatcher(options, callback) {
15
- const watcherId = `watcher_${++this.watcherCounter}`;
9
+ async start(options, callback) {
16
10
  if (!navigator.geolocation) {
17
11
  callback(undefined, {
18
12
  name: "GeolocationError",
19
13
  message: "Geolocation is not supported by this browser",
20
14
  code: "NOT_SUPPORTED",
21
15
  });
22
- return watcherId;
16
+ return;
17
+ }
18
+ if (this.watchId) {
19
+ callback(undefined, {
20
+ name: "GeolocationError",
21
+ message: "Geolocation already started",
22
+ code: "ALREADY_STARTED",
23
+ });
24
+ return;
23
25
  }
24
- const watchId = navigator.geolocation.watchPosition((position) => {
26
+ this.watchId = navigator.geolocation.watchPosition((position) => {
25
27
  const location = {
26
28
  latitude: position.coords.latitude,
27
29
  longitude: position.coords.longitude,
@@ -46,14 +48,11 @@ var capacitorBackgroundGeolocation = (function (exports, core) {
46
48
  timeout: 10000,
47
49
  maximumAge: options.stale ? 300000 : 0,
48
50
  });
49
- this.watchers.set(watcherId, { watchId, callback });
50
- return watcherId;
51
51
  }
52
- async removeWatcher(options) {
53
- const watcher = this.watchers.get(options.id);
54
- if (watcher) {
55
- navigator.geolocation.clearWatch(watcher.watchId);
56
- this.watchers.delete(options.id);
52
+ async stop() {
53
+ if (this.watchId) {
54
+ navigator.geolocation.clearWatch(this.watchId);
55
+ delete this.watchId;
57
56
  }
58
57
  }
59
58
  async openSettings() {
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.js","sources":["esm/index.js","esm/web.js"],"sourcesContent":["import { registerPlugin } from \"@capacitor/core\";\nconst BackgroundGeolocation = registerPlugin(\"BackgroundGeolocation\", {\n web: () => import(\"./web\").then((m) => new m.BackgroundGeolocationWeb()),\n});\nexport * from \"./definitions\";\nexport { BackgroundGeolocation };\n//# sourceMappingURL=index.js.map","import { WebPlugin } from \"@capacitor/core\";\nexport class BackgroundGeolocationWeb extends WebPlugin {\n constructor() {\n super(...arguments);\n this.watchers = new Map();\n this.watcherCounter = 0;\n }\n async addWatcher(options, callback) {\n const watcherId = `watcher_${++this.watcherCounter}`;\n if (!navigator.geolocation) {\n callback(undefined, {\n name: \"GeolocationError\",\n message: \"Geolocation is not supported by this browser\",\n code: \"NOT_SUPPORTED\",\n });\n return watcherId;\n }\n const watchId = navigator.geolocation.watchPosition((position) => {\n const location = {\n latitude: position.coords.latitude,\n longitude: position.coords.longitude,\n accuracy: position.coords.accuracy,\n altitude: position.coords.altitude,\n altitudeAccuracy: position.coords.altitudeAccuracy,\n simulated: false,\n bearing: position.coords.heading,\n speed: position.coords.speed,\n time: position.timestamp,\n };\n callback(location);\n }, (error) => {\n const callbackError = {\n name: \"GeolocationError\",\n message: error.message,\n code: error.code.toString(),\n };\n callback(undefined, callbackError);\n }, {\n enableHighAccuracy: true,\n timeout: 10000,\n maximumAge: options.stale ? 300000 : 0,\n });\n this.watchers.set(watcherId, { watchId, callback });\n return watcherId;\n }\n async removeWatcher(options) {\n const watcher = this.watchers.get(options.id);\n if (watcher) {\n navigator.geolocation.clearWatch(watcher.watchId);\n this.watchers.delete(options.id);\n }\n }\n async openSettings() {\n console.log(\"openSettings: Web implementation cannot open native settings\");\n window.alert(\"Please enable location permissions in your browser settings\");\n }\n}\n//# sourceMappingURL=web.js.map"],"names":["registerPlugin","WebPlugin"],"mappings":"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"}
1
+ {"version":3,"file":"plugin.js","sources":["esm/index.js","esm/web.js"],"sourcesContent":["import { registerPlugin } from \"@capacitor/core\";\nconst BackgroundGeolocation = registerPlugin(\"BackgroundGeolocation\", {\n web: () => import(\"./web\").then((m) => new m.BackgroundGeolocationWeb()),\n});\nexport * from \"./definitions\";\nexport { BackgroundGeolocation };\n//# sourceMappingURL=index.js.map","import { WebPlugin } from \"@capacitor/core\";\nexport class BackgroundGeolocationWeb extends WebPlugin {\n async start(options, callback) {\n if (!navigator.geolocation) {\n callback(undefined, {\n name: \"GeolocationError\",\n message: \"Geolocation is not supported by this browser\",\n code: \"NOT_SUPPORTED\",\n });\n return;\n }\n if (this.watchId) {\n callback(undefined, {\n name: \"GeolocationError\",\n message: \"Geolocation already started\",\n code: \"ALREADY_STARTED\",\n });\n return;\n }\n this.watchId = navigator.geolocation.watchPosition((position) => {\n const location = {\n latitude: position.coords.latitude,\n longitude: position.coords.longitude,\n accuracy: position.coords.accuracy,\n altitude: position.coords.altitude,\n altitudeAccuracy: position.coords.altitudeAccuracy,\n simulated: false,\n bearing: position.coords.heading,\n speed: position.coords.speed,\n time: position.timestamp,\n };\n callback(location);\n }, (error) => {\n const callbackError = {\n name: \"GeolocationError\",\n message: error.message,\n code: error.code.toString(),\n };\n callback(undefined, callbackError);\n }, {\n enableHighAccuracy: true,\n timeout: 10000,\n maximumAge: options.stale ? 300000 : 0,\n });\n }\n async stop() {\n if (this.watchId) {\n navigator.geolocation.clearWatch(this.watchId);\n delete this.watchId;\n }\n }\n async openSettings() {\n console.log(\"openSettings: Web implementation cannot open native settings\");\n window.alert(\"Please enable location permissions in your browser settings\");\n }\n}\n//# sourceMappingURL=web.js.map"],"names":["registerPlugin","WebPlugin"],"mappings":";;;AACK,UAAC,qBAAqB,GAAGA,mBAAc,CAAC,uBAAuB,EAAE;IACtE,IAAI,GAAG,EAAE,MAAM,mDAAe,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,wBAAwB,EAAE,CAAC;IAC5E,CAAC;;ICFM,MAAM,wBAAwB,SAASC,cAAS,CAAC;IACxD,IAAI,MAAM,KAAK,CAAC,OAAO,EAAE,QAAQ,EAAE;IACnC,QAAQ,IAAI,CAAC,SAAS,CAAC,WAAW,EAAE;IACpC,YAAY,QAAQ,CAAC,SAAS,EAAE;IAChC,gBAAgB,IAAI,EAAE,kBAAkB;IACxC,gBAAgB,OAAO,EAAE,8CAA8C;IACvE,gBAAgB,IAAI,EAAE,eAAe;IACrC,aAAa,CAAC;IACd,YAAY;IACZ,QAAQ;IACR,QAAQ,IAAI,IAAI,CAAC,OAAO,EAAE;IAC1B,YAAY,QAAQ,CAAC,SAAS,EAAE;IAChC,gBAAgB,IAAI,EAAE,kBAAkB;IACxC,gBAAgB,OAAO,EAAE,6BAA6B;IACtD,gBAAgB,IAAI,EAAE,iBAAiB;IACvC,aAAa,CAAC;IACd,YAAY;IACZ,QAAQ;IACR,QAAQ,IAAI,CAAC,OAAO,GAAG,SAAS,CAAC,WAAW,CAAC,aAAa,CAAC,CAAC,QAAQ,KAAK;IACzE,YAAY,MAAM,QAAQ,GAAG;IAC7B,gBAAgB,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,QAAQ;IAClD,gBAAgB,SAAS,EAAE,QAAQ,CAAC,MAAM,CAAC,SAAS;IACpD,gBAAgB,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,QAAQ;IAClD,gBAAgB,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,QAAQ;IAClD,gBAAgB,gBAAgB,EAAE,QAAQ,CAAC,MAAM,CAAC,gBAAgB;IAClE,gBAAgB,SAAS,EAAE,KAAK;IAChC,gBAAgB,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,OAAO;IAChD,gBAAgB,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,KAAK;IAC5C,gBAAgB,IAAI,EAAE,QAAQ,CAAC,SAAS;IACxC,aAAa;IACb,YAAY,QAAQ,CAAC,QAAQ,CAAC;IAC9B,QAAQ,CAAC,EAAE,CAAC,KAAK,KAAK;IACtB,YAAY,MAAM,aAAa,GAAG;IAClC,gBAAgB,IAAI,EAAE,kBAAkB;IACxC,gBAAgB,OAAO,EAAE,KAAK,CAAC,OAAO;IACtC,gBAAgB,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,QAAQ,EAAE;IAC3C,aAAa;IACb,YAAY,QAAQ,CAAC,SAAS,EAAE,aAAa,CAAC;IAC9C,QAAQ,CAAC,EAAE;IACX,YAAY,kBAAkB,EAAE,IAAI;IACpC,YAAY,OAAO,EAAE,KAAK;IAC1B,YAAY,UAAU,EAAE,OAAO,CAAC,KAAK,GAAG,MAAM,GAAG,CAAC;IAClD,SAAS,CAAC;IACV,IAAI;IACJ,IAAI,MAAM,IAAI,GAAG;IACjB,QAAQ,IAAI,IAAI,CAAC,OAAO,EAAE;IAC1B,YAAY,SAAS,CAAC,WAAW,CAAC,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC;IAC1D,YAAY,OAAO,IAAI,CAAC,OAAO;IAC/B,QAAQ;IACR,IAAI;IACJ,IAAI,MAAM,YAAY,GAAG;IACzB,QAAQ,OAAO,CAAC,GAAG,CAAC,8DAA8D,CAAC;IACnF,QAAQ,MAAM,CAAC,KAAK,CAAC,6DAA6D,CAAC;IACnF,IAAI;IACJ;;;;;;;;;;;;;;;"}
@@ -2,7 +2,7 @@
2
2
  #import <Capacitor/Capacitor.h>
3
3
 
4
4
  CAP_PLUGIN(BackgroundGeolocation, "BackgroundGeolocation",
5
- CAP_PLUGIN_METHOD(addWatcher, CAPPluginReturnCallback);
6
- CAP_PLUGIN_METHOD(removeWatcher, CAPPluginReturnPromise);
5
+ CAP_PLUGIN_METHOD(start, CAPPluginReturnCallback);
6
+ CAP_PLUGIN_METHOD(stop, CAPPluginReturnPromise);
7
7
  CAP_PLUGIN_METHOD(openSettings, CAPPluginReturnPromise);
8
8
  )
@@ -33,63 +33,41 @@ func formatLocation(_ location: CLLocation) -> PluginCallResultData {
33
33
  ]
34
34
  }
35
35
 
36
- class Watcher {
37
- let callbackId: String
38
- let locationManager: CLLocationManager = CLLocationManager()
39
- private let created = Date()
40
- private let allowStale: Bool
41
- private var isUpdatingLocation: Bool = false
42
- init(_ id: String, stale: Bool) {
43
- callbackId = id
44
- allowStale = stale
45
- }
46
- func start() {
47
- // Avoid unnecessary calls to startUpdatingLocation, which can
48
- // result in extraneous invocations of didFailWithError.
49
- if !isUpdatingLocation {
50
- locationManager.startUpdatingLocation()
51
- isUpdatingLocation = true
52
- }
53
- }
54
- func stop() {
55
- if isUpdatingLocation {
56
- locationManager.stopUpdatingLocation()
57
- isUpdatingLocation = false
58
- }
59
- }
60
- func isLocationValid(_ location: CLLocation) -> Bool {
61
- return (
62
- allowStale ||
63
- location.timestamp >= created
64
- )
65
- }
66
- }
67
-
68
36
  @objc(BackgroundGeolocation)
69
37
  public class BackgroundGeolocation: CAPPlugin, CLLocationManagerDelegate {
70
- private var watchers = [Watcher]()
38
+ private var locationManager: CLLocationManager?
39
+ private var created: Date?
40
+ private var allowStale: Bool = false
41
+ private var isUpdatingLocation: Bool = false
42
+ private var activeCallbackId: String?
71
43
 
72
44
  @objc override public func load() {
73
45
  UIDevice.current.isBatteryMonitoringEnabled = true
74
46
  }
75
47
 
76
- @objc func addWatcher(_ call: CAPPluginCall) {
48
+ @objc func start(_ call: CAPPluginCall) {
77
49
  call.keepAlive = true
78
50
 
79
51
  // CLLocationManager requires main thread
80
52
  DispatchQueue.main.async {
53
+ // Check if already started
54
+ if self.locationManager != nil {
55
+ return call.reject("Location tracking already started", "ALREADY_STARTED")
56
+ }
57
+ // Create fresh location manager and initialize date
58
+ self.locationManager = CLLocationManager()
59
+ self.locationManager!.delegate = self
60
+ self.created = Date()
61
+
81
62
  let background = call.getString("backgroundMessage") != nil
82
- let watcher = Watcher(
83
- call.callbackId,
84
- stale: call.getBool("stale") ?? false
85
- )
86
- let manager = watcher.locationManager
87
- manager.delegate = self
63
+ self.allowStale = call.getBool("stale") ?? false
64
+ self.activeCallbackId = call.callbackId
65
+
88
66
  let externalPower = [
89
67
  .full,
90
68
  .charging
91
69
  ].contains(UIDevice.current.batteryState)
92
- manager.desiredAccuracy = (
70
+ self.locationManager!.desiredAccuracy = (
93
71
  externalPower
94
72
  ? kCLLocationAccuracyBestForNavigation
95
73
  : kCLLocationAccuracyBest
@@ -100,11 +78,11 @@ public class BackgroundGeolocation: CAPPlugin, CLLocationManagerDelegate {
100
78
  if distanceFilter == nil || distanceFilter == 0 {
101
79
  distanceFilter = kCLDistanceFilterNone
102
80
  }
103
- manager.distanceFilter = distanceFilter!
104
- manager.allowsBackgroundLocationUpdates = background
105
- manager.showsBackgroundLocationIndicator = background
106
- manager.pausesLocationUpdatesAutomatically = false
107
- self.watchers.append(watcher)
81
+ self.locationManager!.distanceFilter = distanceFilter!
82
+ self.locationManager!.allowsBackgroundLocationUpdates = background
83
+ self.locationManager!.showsBackgroundLocationIndicator = background
84
+ self.locationManager!.pausesLocationUpdatesAutomatically = false
85
+
108
86
  if call.getBool("requestPermissions") != false {
109
87
  let status = CLLocationManager.authorizationStatus()
110
88
  if [
@@ -114,35 +92,35 @@ public class BackgroundGeolocation: CAPPlugin, CLLocationManagerDelegate {
114
92
  ].contains(status) {
115
93
  return (
116
94
  background
117
- ? manager.requestAlwaysAuthorization()
118
- : manager.requestWhenInUseAuthorization()
95
+ ? self.locationManager!.requestAlwaysAuthorization()
96
+ : self.locationManager!.requestWhenInUseAuthorization()
119
97
  )
120
98
  }
121
99
  if background && status == .authorizedWhenInUse {
122
100
  // Attempt to escalate.
123
- manager.requestAlwaysAuthorization()
101
+ self.locationManager!.requestAlwaysAuthorization()
124
102
  }
125
103
  }
126
- return watcher.start()
104
+ return self.startUpdatingLocation()
127
105
  }
128
106
  }
129
107
 
130
- @objc func removeWatcher(_ call: CAPPluginCall) {
108
+ @objc func stop(_ call: CAPPluginCall) {
131
109
  // CLLocationManager requires main thread
132
110
  DispatchQueue.main.async {
133
- if let callbackId = call.getString("id") {
134
- if let index = self.watchers.firstIndex(
135
- where: { $0.callbackId == callbackId }
136
- ) {
137
- self.watchers[index].locationManager.stopUpdatingLocation()
138
- self.watchers.remove(at: index)
139
- }
111
+ self.stopUpdatingLocation()
112
+
113
+ self.locationManager?.delegate = nil
114
+ self.locationManager = nil
115
+ self.created = nil
116
+
117
+ if let callbackId = self.activeCallbackId {
140
118
  if let savedCall = self.bridge?.savedCall(withID: callbackId) {
141
119
  self.bridge?.releaseCall(savedCall)
142
120
  }
143
- return call.resolve()
121
+ self.activeCallbackId = nil
144
122
  }
145
- return call.reject("No callback ID")
123
+ return call.resolve()
146
124
  }
147
125
  }
148
126
 
@@ -169,46 +147,67 @@ public class BackgroundGeolocation: CAPPlugin, CLLocationManagerDelegate {
169
147
  }
170
148
  }
171
149
 
150
+ private func startUpdatingLocation() {
151
+ // Avoid unnecessary calls to startUpdatingLocation, which can
152
+ // result in extraneous invocations of didFailWithError.
153
+ if !isUpdatingLocation, let manager = locationManager {
154
+ manager.startUpdatingLocation()
155
+ isUpdatingLocation = true
156
+ }
157
+ }
158
+
159
+ private func stopUpdatingLocation() {
160
+ if isUpdatingLocation, let manager = locationManager {
161
+ manager.stopUpdatingLocation()
162
+ isUpdatingLocation = false
163
+ }
164
+ }
165
+
166
+ private func isLocationValid(_ location: CLLocation) -> Bool {
167
+ guard let created = created else { return allowStale }
168
+ return (
169
+ allowStale ||
170
+ location.timestamp >= created
171
+ )
172
+ }
173
+
172
174
  public func locationManager(
173
175
  _ manager: CLLocationManager,
174
176
  didFailWithError error: Error
175
177
  ) {
176
- if let watcher = self.watchers.first(
177
- where: { $0.locationManager == manager }
178
- ) {
179
- if let call = self.bridge?.savedCall(withID: watcher.callbackId) {
180
- if let clErr = error as? CLError {
181
- if clErr.code == .locationUnknown {
182
- // This error is sometimes sent by the manager if
183
- // it cannot get a fix immediately.
184
- return
185
- } else if clErr.code == .denied {
186
- watcher.stop()
187
- return call.reject(
188
- "Permission denied.",
189
- "NOT_AUTHORIZED"
190
- )
191
- }
192
- }
193
- return call.reject(error.localizedDescription, nil, error)
178
+ guard let callbackId = activeCallbackId,
179
+ let call = self.bridge?.savedCall(withID: callbackId) else {
180
+ return
181
+ }
182
+
183
+ if let clErr = error as? CLError {
184
+ if clErr.code == .locationUnknown {
185
+ // This error is sometimes sent by the manager if
186
+ // it cannot get a fix immediately.
187
+ return
188
+ } else if clErr.code == .denied {
189
+ stopUpdatingLocation()
190
+ return call.reject(
191
+ "Permission denied.",
192
+ "NOT_AUTHORIZED"
193
+ )
194
194
  }
195
195
  }
196
+ return call.reject(error.localizedDescription, nil, error)
196
197
  }
197
198
 
198
199
  public func locationManager(
199
200
  _ manager: CLLocationManager,
200
201
  didUpdateLocations locations: [CLLocation]
201
202
  ) {
202
- if let location = locations.last {
203
- if let watcher = self.watchers.first(
204
- where: { $0.locationManager == manager }
205
- ) {
206
- if watcher.isLocationValid(location) {
207
- if let call = self.bridge?.savedCall(withID: watcher.callbackId) {
208
- return call.resolve(formatLocation(location))
209
- }
210
- }
211
- }
203
+ guard let location = locations.last,
204
+ let callbackId = activeCallbackId,
205
+ let call = self.bridge?.savedCall(withID: callbackId) else {
206
+ return
207
+ }
208
+
209
+ if isLocationValid(location) {
210
+ return call.resolve(formatLocation(location))
212
211
  }
213
212
  }
214
213
 
@@ -220,11 +219,7 @@ public class BackgroundGeolocation: CAPPlugin, CLLocationManagerDelegate {
220
219
  // it is on iOS 14 when the permissions dialog is presented, we ignore
221
220
  // it.
222
221
  if status != .notDetermined {
223
- if let watcher = self.watchers.first(
224
- where: { $0.locationManager == manager }
225
- ) {
226
- return watcher.start()
227
- }
222
+ startUpdatingLocation()
228
223
  }
229
224
  }
230
225
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@capgo/background-geolocation",
3
- "version": "7.0.8",
3
+ "version": "7.0.9",
4
4
  "description": "Receive geolocation updates even while the app is in the background.",
5
5
  "main": "dist/plugin.cjs.js",
6
6
  "module": "dist/esm/index.js",