@azatek/background-geolocation 1.0.0 → 7.0.1

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
@@ -35,10 +35,31 @@ const watcherId = await BackgroundGeolocation.addWatcher({
35
35
 
36
36
  ## Accuracy Modes
37
37
 
38
- - **LocationAccuracy.HIGH (100)**: GPS only - High battery usage, best accuracy
39
- - **LocationAccuracy.BALANCED (102)**: GPS + Network - Medium battery, good accuracy
40
- - **LocationAccuracy.LOW (104)**: Network only - Low battery, approximate location
41
- - **LocationAccuracy.PASSIVE (105)**: Minimal battery, uses other apps' location requests
38
+ | Mode | Value | Description | Accuracy Level |
39
+ |------|-------|-------------|----------------|
40
+ | **HIGH** | 100 | Best accuracy, high battery usage | Android: PRIORITY_HIGH_ACCURACY<br>iOS: kCLLocationAccuracyBest |
41
+ | **BALANCED** | 102 | Good accuracy (default) | Android: PRIORITY_BALANCED_POWER_ACCURACY<br>iOS: kCLLocationAccuracyNearestTenMeters |
42
+ | **LOW** | 104 | Approximate location | Android: PRIORITY_LOW_POWER<br>iOS: kCLLocationAccuracyHundredMeters |
43
+ | **PASSIVE** | 105 | Minimal battery | Android: PRIORITY_PASSIVE<br>iOS: kCLLocationAccuracyThreeKilometers |
44
+
45
+ ### Platform Behavior
46
+
47
+ **Both platforms now behave identically:**
48
+ - Location updates are triggered **only by distance changes**, not time intervals
49
+ - `distanceFilter: 50` → Updates only when device moves 50+ meters
50
+ - `distanceFilter: 0` → Updates on any movement (controlled by accuracy setting)
51
+
52
+ **Important:**
53
+ - ⚠️ With `distanceFilter > 0`, you will **NOT** receive updates when stationary
54
+ - ✅ This matches iOS behavior and saves battery
55
+ - 💡 Set `distanceFilter: 0` if you need updates even when stationary
56
+
57
+ **Android-specific:**
58
+ - Uses `FusedLocationProviderClient` with very large time interval to effectively disable time-based updates
59
+
60
+ **iOS-specific:**
61
+ - Uses `CLLocationManager.distanceFilter` natively
62
+ - HIGH mode automatically switches to `kCLLocationAccuracyBestForNavigation` when device is charging
42
63
 
43
64
  ## Original Usage
44
65
 
@@ -42,7 +42,8 @@ import androidx.localbroadcastmanager.content.LocalBroadcastManager;
42
42
  @Permission(
43
43
  strings = {
44
44
  Manifest.permission.ACCESS_COARSE_LOCATION,
45
- Manifest.permission.ACCESS_FINE_LOCATION
45
+ Manifest.permission.ACCESS_FINE_LOCATION,
46
+ Manifest.permission.FOREGROUND_SERVICE_LOCATION
46
47
  },
47
48
  alias = "location"
48
49
  )
@@ -70,23 +71,12 @@ public class BackgroundGeolocation extends Plugin {
70
71
  } catch (SecurityException ignore) {}
71
72
  }
72
73
 
73
- @PluginMethod(returnType = PluginMethod.RETURN_CALLBACK)
74
- public void addWatcher(final PluginCall call) {
75
- if (service == null) {
76
- call.reject("Service not running.");
74
+ private void startWatcher(PluginCall call) {
75
+ if (!isLocationEnabled(getContext())) {
76
+ call.reject("Location services disabled.", "NOT_AUTHORIZED");
77
77
  return;
78
78
  }
79
- call.setKeepAlive(true);
80
79
 
81
- if (getPermissionState("location") != PermissionState.GRANTED) {
82
- if (call.getBoolean("requestPermissions", true)) {
83
- requestPermissionForAlias("location", call, "locationPermissionsCallback");
84
- } else {
85
- call.reject("Permission denied.", "NOT_AUTHORIZED");
86
- }
87
- } else if (!isLocationEnabled(getContext())) {
88
- call.reject("Location services disabled.", "NOT_AUTHORIZED");
89
- }
90
80
  if (call.getBoolean("stale", false)) {
91
81
  fetchLastLocation(call);
92
82
  }
@@ -164,6 +154,26 @@ public class BackgroundGeolocation extends Plugin {
164
154
  );
165
155
  }
166
156
 
157
+ @PluginMethod(returnType = PluginMethod.RETURN_CALLBACK)
158
+ public void addWatcher(final PluginCall call) {
159
+ if (service == null) {
160
+ call.reject("Service not running.");
161
+ return;
162
+ }
163
+ call.setKeepAlive(true);
164
+
165
+ if (getPermissionState("location") != PermissionState.GRANTED) {
166
+ if (call.getBoolean("requestPermissions", true)) {
167
+ requestPermissionForAlias("location", call, "locationPermissionsCallback");
168
+ } else {
169
+ call.reject("Permission denied.", "NOT_AUTHORIZED");
170
+ }
171
+ return;
172
+ }
173
+
174
+ startWatcher(call);
175
+ }
176
+
167
177
  @PermissionCallback
168
178
  private void locationPermissionsCallback(PluginCall call) {
169
179
 
@@ -171,15 +181,13 @@ public class BackgroundGeolocation extends Plugin {
171
181
  call.reject("User denied location permission", "NOT_AUTHORIZED");
172
182
  return;
173
183
  }
174
- if (call.getBoolean("stale", false)) {
175
- fetchLastLocation(call);
176
- }
184
+
177
185
  if (service != null) {
178
186
  service.onPermissionsGranted();
179
- // The handleOnResume method will now be called, and we don't need it to call
180
- // service.onPermissionsGranted again so we reset this flag.
181
187
  stoppedWithoutPermissions = false;
182
188
  }
189
+
190
+ startWatcher(call);
183
191
  }
184
192
 
185
193
  @PluginMethod()
@@ -16,6 +16,7 @@ import com.google.android.gms.location.LocationCallback;
16
16
  import com.google.android.gms.location.LocationRequest;
17
17
  import com.google.android.gms.location.LocationResult;
18
18
  import com.google.android.gms.location.LocationServices;
19
+ import com.google.android.gms.location.Priority;
19
20
 
20
21
  import java.util.HashSet;
21
22
 
@@ -84,35 +85,32 @@ public class BackgroundGeolocationService extends Service {
84
85
 
85
86
  // Map accuracy enum to Android Priority
86
87
  int priority;
87
- long interval;
88
-
88
+
89
89
  switch (accuracy) {
90
90
  case 100: // HIGH
91
91
  priority = Priority.PRIORITY_HIGH_ACCURACY;
92
- interval = 5000; // 5 seconds
93
92
  break;
94
93
  case 102: // BALANCED (Default)
95
94
  priority = Priority.PRIORITY_BALANCED_POWER_ACCURACY;
96
- interval = 10000; // 10 seconds
97
95
  break;
98
96
  case 104: // LOW
99
97
  priority = Priority.PRIORITY_LOW_POWER;
100
- interval = 30000; // 30 seconds
101
98
  break;
102
99
  case 105: // PASSIVE
103
100
  priority = Priority.PRIORITY_PASSIVE;
104
- interval = 60000; // 60 seconds
105
101
  break;
106
102
  default:
107
103
  priority = Priority.PRIORITY_BALANCED_POWER_ACCURACY;
108
- interval = 10000;
109
104
  }
110
-
111
- // Use modern LocationRequest.Builder API
105
+
106
+ // Match iOS behavior: Only update based on distance, not time intervals
107
+ // When distanceFilter is 0, use a minimal interval to get updates
108
+ // When distanceFilter > 0, use a very large interval so only distance triggers updates
109
+ long interval = (distanceFilter > 0) ? Long.MAX_VALUE : 1000;
110
+
112
111
  LocationRequest locationRequest = new LocationRequest.Builder(priority, interval)
113
112
  .setMinUpdateDistanceMeters(distanceFilter)
114
113
  .setWaitForAccurateLocation(false)
115
- .setMaxUpdateDelayMillis(interval)
116
114
  .build();
117
115
 
118
116
  LocationCallback callback = new LocationCallback(){
@@ -129,7 +127,7 @@ public class BackgroundGeolocationService extends Service {
129
127
  @Override
130
128
  public void onLocationAvailability(LocationAvailability availability) {
131
129
  if (!availability.isLocationAvailable()) {
132
- Logger.debug("Location not available");
130
+ Logger.warn("Location not available - check if GPS is enabled");
133
131
  }
134
132
  }
135
133
  };
@@ -151,7 +149,9 @@ public class BackgroundGeolocationService extends Service {
151
149
  watcher.locationCallback,
152
150
  null
153
151
  );
154
- } catch (SecurityException ignore) {}
152
+ } catch (SecurityException e) {
153
+ Logger.error("SecurityException when requesting location updates", e);
154
+ }
155
155
 
156
156
  // Promote the service to the foreground if necessary.
157
157
  // Ideally we would only call 'startForeground' if the service is not already
package/index.js ADDED
@@ -0,0 +1,6 @@
1
+ export const LocationAccuracy = {
2
+ HIGH: 100,
3
+ BALANCED: 102,
4
+ LOW: 104,
5
+ PASSIVE: 105
6
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@azatek/background-geolocation",
3
- "version": "1.0.0",
3
+ "version": "7.0.1",
4
4
  "description": "Capacitor plugin for background geolocation tracking with configurable GPS accuracy modes (HIGH/BALANCED/LOW/PASSIVE) for battery optimization. Fork of @capacitor-community/background-geolocation with enhanced accuracy control.",
5
5
  "keywords": [
6
6
  "capacitor",
@@ -21,8 +21,18 @@
21
21
  },
22
22
  "author": "AzaTek",
23
23
  "license": "MIT",
24
+ "main": "index.js",
25
+ "module": "index.js",
24
26
  "types": "definitions.d.ts",
27
+ "exports": {
28
+ ".": {
29
+ "types": "./definitions.d.ts",
30
+ "import": "./index.js",
31
+ "require": "./index.js"
32
+ }
33
+ },
25
34
  "files": [
35
+ "index.js",
26
36
  "CapacitorCommunityBackgroundGeolocation.podspec",
27
37
  "Package.swift",
28
38
  "android/build.gradle",