@josuelmm/cordova-background-geolocation 4.2.3 → 4.5.2

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.
Files changed (103) hide show
  1. package/.npmignore +11 -0
  2. package/CHANGELOG.md +261 -0
  3. package/README.md +306 -115
  4. package/android/CDVBackgroundGeolocation/src/main/java/com/marianhello/bgloc/cordova/ConfigMapper.java +34 -0
  5. package/android/CDVBackgroundGeolocation/src/main/java/com/tenforwardconsulting/bgloc/cordova/BackgroundGeolocationPlugin.java +61 -1
  6. package/android/common/src/main/AndroidManifest.xml +1 -1
  7. package/android/common/src/main/java/com/marianhello/bgloc/BootCompletedReceiver.java +20 -3
  8. package/android/common/src/main/java/com/marianhello/bgloc/Config.java +87 -1
  9. package/android/common/src/main/java/com/marianhello/bgloc/data/BackgroundLocation.java +94 -0
  10. package/android/common/src/main/java/com/marianhello/bgloc/data/ConfigJsonMapper.java +211 -0
  11. package/android/common/src/main/java/com/marianhello/bgloc/data/LocationTemplateFactory.java +6 -0
  12. package/android/common/src/main/java/com/marianhello/bgloc/data/sqlite/SQLiteConfigurationContract.java +5 -1
  13. package/android/common/src/main/java/com/marianhello/bgloc/data/sqlite/SQLiteConfigurationDAO.java +32 -1
  14. package/android/common/src/main/java/com/marianhello/bgloc/data/sqlite/SQLiteLocationContract.java +12 -2
  15. package/android/common/src/main/java/com/marianhello/bgloc/data/sqlite/SQLiteLocationDAO.java +33 -2
  16. package/android/common/src/main/java/com/marianhello/bgloc/data/sqlite/SQLiteOpenHelper.java +15 -1
  17. package/android/common/src/main/java/com/marianhello/bgloc/provider/AbstractLocationProvider.java +48 -1
  18. package/android/common/src/main/java/com/marianhello/bgloc/provider/ActivityRecognitionLocationProvider.java +105 -6
  19. package/android/common/src/main/java/com/marianhello/bgloc/provider/DistanceFilterLocationProvider.java +336 -250
  20. package/android/common/src/main/java/com/marianhello/bgloc/provider/RawLocationProvider.java +69 -19
  21. package/android/common/src/main/java/com/marianhello/bgloc/service/LocationServiceImpl.java +246 -21
  22. package/android/common/src/main/java/com/marianhello/bgloc/service/LocationServiceProxy.java +5 -2
  23. package/android/common/src/main/java/com/marianhello/bgloc/sync/BatchManager.java +46 -13
  24. package/ios/CDVBackgroundGeolocation/CDVBackgroundGeolocation.m +23 -1
  25. package/ios/common/BackgroundGeolocation/MAURActivityLocationProvider.m +208 -70
  26. package/ios/common/BackgroundGeolocation/MAURBackgroundGeolocationFacade.m +132 -5
  27. package/ios/common/BackgroundGeolocation/MAURBackgroundSync.m +20 -0
  28. package/ios/common/BackgroundGeolocation/MAURConfig.h +7 -0
  29. package/ios/common/BackgroundGeolocation/MAURConfig.m +37 -2
  30. package/ios/common/BackgroundGeolocation/MAURConfigurationContract.h +3 -0
  31. package/ios/common/BackgroundGeolocation/MAURConfigurationContract.m +3 -1
  32. package/ios/common/BackgroundGeolocation/MAURDistanceFilterLocationProvider.m +10 -1
  33. package/ios/common/BackgroundGeolocation/MAURGeolocationOpenHelper.m +15 -1
  34. package/ios/common/BackgroundGeolocation/MAURLocation.h +12 -0
  35. package/ios/common/BackgroundGeolocation/MAURLocation.m +33 -4
  36. package/ios/common/BackgroundGeolocation/MAURLocationContract.h +4 -0
  37. package/ios/common/BackgroundGeolocation/MAURLocationContract.m +5 -1
  38. package/ios/common/BackgroundGeolocation/MAURLocationManager.m +19 -1
  39. package/ios/common/BackgroundGeolocation/MAURPostLocationTask.h +9 -0
  40. package/ios/common/BackgroundGeolocation/MAURPostLocationTask.m +59 -1
  41. package/ios/common/BackgroundGeolocation/MAURRawLocationProvider.m +10 -1
  42. package/ios/common/BackgroundGeolocation/MAURSQLiteConfigurationDAO.m +54 -4
  43. package/ios/common/BackgroundGeolocation/MAURSQLiteLocationDAO.h +12 -0
  44. package/ios/common/BackgroundGeolocation/MAURSQLiteLocationDAO.m +125 -5
  45. package/package.json +31 -1
  46. package/plugin.xml +3 -10
  47. package/www/BackgroundGeolocation.d.ts +143 -3
  48. package/www/BackgroundGeolocation.js +11 -4
  49. package/CLAUDE.md +0 -56
  50. package/HISTORY.md +0 -871
  51. package/android/CDVBackgroundGeolocation/src/test/java/com/marianhello/ConfigMapperTest.java +0 -220
  52. package/android/common/src/androidTest/java/com/marianhello/bgloc/BackgroundGeolocationFacadeTest.java +0 -45
  53. package/android/common/src/androidTest/java/com/marianhello/bgloc/BatchManagerTest.java +0 -570
  54. package/android/common/src/androidTest/java/com/marianhello/bgloc/ConfigTest.java +0 -76
  55. package/android/common/src/androidTest/java/com/marianhello/bgloc/ContentProviderLocationDAOTest.java +0 -437
  56. package/android/common/src/androidTest/java/com/marianhello/bgloc/DBLogReaderTest.java +0 -95
  57. package/android/common/src/androidTest/java/com/marianhello/bgloc/LocationContentProviderTest.java +0 -159
  58. package/android/common/src/androidTest/java/com/marianhello/bgloc/LocationServiceProxyTest.java +0 -161
  59. package/android/common/src/androidTest/java/com/marianhello/bgloc/LocationServiceTest.java +0 -247
  60. package/android/common/src/androidTest/java/com/marianhello/bgloc/SQLiteConfigurationDAOTest.java +0 -200
  61. package/android/common/src/androidTest/java/com/marianhello/bgloc/SQLiteLocationDAOTest.java +0 -457
  62. package/android/common/src/androidTest/java/com/marianhello/bgloc/SQLiteLocationDAOThreadTest.java +0 -96
  63. package/android/common/src/androidTest/java/com/marianhello/bgloc/SQLiteOpenHelperTest.java +0 -225
  64. package/android/common/src/androidTest/java/com/marianhello/bgloc/TestPluginDelegate.java +0 -46
  65. package/android/common/src/androidTest/java/com/marianhello/bgloc/TestResourceResolver.java +0 -14
  66. package/android/common/src/androidTest/java/com/marianhello/bgloc/provider/MockLocationProvider.java +0 -50
  67. package/android/common/src/androidTest/java/com/marianhello/bgloc/provider/TestLocationProviderFactory.java +0 -17
  68. package/android/common/src/androidTest/java/com/marianhello/bgloc/sqlite/SQLiteOpenHelper10.java +0 -92
  69. package/android/common/src/androidTest/java/com/marianhello/bgloc/test/LocationProviderTestCase.java +0 -107
  70. package/android/common/src/androidTest/java/com/marianhello/bgloc/test/TestConstants.java +0 -5
  71. package/android/common/src/test/java/com/marianhello/backgroundgeolocation/ArrayListLocationTemplateTest.java +0 -82
  72. package/android/common/src/test/java/com/marianhello/backgroundgeolocation/BackgroundLocationTest.java +0 -128
  73. package/android/common/src/test/java/com/marianhello/backgroundgeolocation/ConfigTest.java +0 -191
  74. package/android/common/src/test/java/com/marianhello/backgroundgeolocation/DBLogReaderTest.java +0 -37
  75. package/android/common/src/test/java/com/marianhello/backgroundgeolocation/HashMapLocationTemplateTest.java +0 -216
  76. package/android/common/src/test/java/com/marianhello/backgroundgeolocation/HttpPostServiceTest.java +0 -223
  77. package/android/common/src/test/java/com/marianhello/backgroundgeolocation/LocationTemplateFactoryTest.java +0 -50
  78. package/android/common/src/test/java/com/marianhello/backgroundgeolocation/PostLocationTaskTest.java +0 -180
  79. package/android/common/src/test/java/com/marianhello/backgroundgeolocation/TestHelper.java +0 -16
  80. package/ios/common/BackgroundGeolocation/SOMotionDetector/CHANGELOG.md +0 -2
  81. package/ios/common/BackgroundGeolocation/SOMotionDetector/LICENSE +0 -21
  82. package/ios/common/BackgroundGeolocation/SOMotionDetector/README.md +0 -135
  83. package/ios/common/BackgroundGeolocation/SOMotionDetector/SOLocationManager.h +0 -80
  84. package/ios/common/BackgroundGeolocation/SOMotionDetector/SOLocationManager.m +0 -147
  85. package/ios/common/BackgroundGeolocation/SOMotionDetector/SOMotionActivity.h +0 -30
  86. package/ios/common/BackgroundGeolocation/SOMotionDetector/SOMotionActivity.m +0 -42
  87. package/ios/common/BackgroundGeolocation/SOMotionDetector/SOMotionDetector.h +0 -99
  88. package/ios/common/BackgroundGeolocation/SOMotionDetector/SOMotionDetector.m +0 -327
  89. package/ios/common/BackgroundGeolocation/SOMotionDetector/SOStepDetector.h +0 -44
  90. package/ios/common/BackgroundGeolocation/SOMotionDetector/SOStepDetector.m +0 -94
  91. package/ios/common/BackgroundGeolocationTests/Info.plist +0 -24
  92. package/ios/common/BackgroundGeolocationTests/MAURBackgroundLocationTest.m +0 -185
  93. package/ios/common/BackgroundGeolocationTests/MAURConfigTest.m +0 -161
  94. package/ios/common/BackgroundGeolocationTests/MAURGeolocationOpenHelperTest.m +0 -102
  95. package/ios/common/BackgroundGeolocationTests/MAURLocationTest.m +0 -216
  96. package/ios/common/BackgroundGeolocationTests/MAURLocationUploaderTest.m +0 -55
  97. package/ios/common/BackgroundGeolocationTests/MAURLogReaderTest.m +0 -43
  98. package/ios/common/BackgroundGeolocationTests/MAURSQLiteConfigurationDAOTest.m +0 -102
  99. package/ios/common/BackgroundGeolocationTests/MAURSQLiteHelperTest.m +0 -41
  100. package/ios/common/BackgroundGeolocationTests/MAURSQLiteLocationDAOTests.m +0 -240
  101. package/ios/common/BackgroundGeolocationTests/MAURSQLiteLocationDAOThreadTest.m +0 -84
  102. package/ios/common/BackgroundGeolocationTests/MAURSQLiteOpenHelperTest.m +0 -144
  103. package/ios/common/scripts/xcode-refactor.js +0 -184
package/README.md CHANGED
@@ -179,6 +179,93 @@ BackgroundGeolocation.FOREGROUND_MODE
179
179
 
180
180
  Set your preferred provider, accuracy, intervals, and optional server URLs. All options are optional; you can reconfigure later with a subset (options are merged).
181
181
 
182
+ #### 1.1 `locationProvider` — which engine produces the fixes
183
+
184
+ This is the **most important choice**. It changes how often, how accurately, and how cheaply (battery-wise) the plugin gets locations. Three values, pick **one**:
185
+
186
+ | Value | Constant | Internals | When to use |
187
+ |---|---|---|---|
188
+ | `0` | `BackgroundGeolocation.DISTANCE_FILTER_PROVIDER` (default) | **Hybrid (v4.5.2+)**: `FusedLocationProviderClient` cuando Google Play Services está disponible, fallback automático a `LocationManager` cuando no (Huawei/HMS, AOSP, ChinaROMs). Implementa una **state machine de detección stationary**: mientras se mueve muestrea normal; al detenerse usa **polling lazy** (3 min) y **polling aggressive** (1 min cerca del borde) vía `AlarmManager`. **No usa geofences** (eliminados por decisión de producto); la salida del estado stationary se detecta solo por polling. | **Default para la mayoría de apps.** Tracking personal, couriers de delivery, cualquiera que necesite ubicación sin drenar batería al estar parado. **Funciona con o sin Google Play Services.** |
189
+ | `1` | `BackgroundGeolocation.ACTIVITY_PROVIDER` | Google Play Services `FusedLocationProviderClient` + **Activity Recognition** (walking / driving / still). When `STILL` is detected, the provider stops requesting fixes; when activity resumes, it restarts. Uses `LocationRequest.Builder` + `Priority.PRIORITY_HIGH_ACCURACY` (or balanced, per `desiredAccuracy`). | Apps where the **activity matters** (fitness, fleet, ride-hailing). Best battery profile when the user spends a lot of time still. **Requires Google Play Services** on the device and `ACTIVITY_RECOGNITION` runtime permission on Android 10+. |
190
+ | `2` | `BackgroundGeolocation.RAW_PROVIDER` | Direct `LocationManager` requests with **no stationary detection, no batching, no filtering**. Every fix the OS produces is forwarded. | Vehicle tracking with a **constant interval**, dashcams, anything where you want raw GPS without the plugin trying to be smart. **Highest battery cost.** |
191
+
192
+ ```js
193
+ // Recommended for personal apps (Life360-style)
194
+ BackgroundGeolocation.configure({
195
+ locationProvider: BackgroundGeolocation.DISTANCE_FILTER_PROVIDER,
196
+ desiredAccuracy: BackgroundGeolocation.MEDIUM_ACCURACY,
197
+ distanceFilter: 50,
198
+ stationaryRadius: 50
199
+ });
200
+
201
+ // Recommended for fleet/vehicle tracking
202
+ BackgroundGeolocation.configure({
203
+ locationProvider: BackgroundGeolocation.ACTIVITY_PROVIDER,
204
+ desiredAccuracy: BackgroundGeolocation.HIGH_ACCURACY,
205
+ interval: 15000,
206
+ fastestInterval: 10000,
207
+ activitiesInterval: 30000
208
+ });
209
+
210
+ // Raw — every fix, no smart filtering
211
+ BackgroundGeolocation.configure({
212
+ locationProvider: BackgroundGeolocation.RAW_PROVIDER,
213
+ desiredAccuracy: BackgroundGeolocation.HIGH_ACCURACY,
214
+ interval: 5000
215
+ });
216
+ ```
217
+
218
+ **iOS note:** all three constants exist for API parity, but iOS internally always uses `CLLocationManager`. The plugin maps `DISTANCE_FILTER_PROVIDER` and `RAW_PROVIDER` to standard location updates, and `ACTIVITY_PROVIDER` enables `CMMotionActivityManager` for activity detection on top.
219
+
220
+ #### 1.2 `startOnBoot` — survive a reboot (Android only)
221
+
222
+ When `true`, the plugin re-arms tracking automatically after the device reboots or after an app update — without the user opening the app.
223
+
224
+ **How it works internally:**
225
+
226
+ 1. The plugin registers a `BootCompletedReceiver` that listens for `BOOT_COMPLETED`, `QUICKBOOT_POWERON` (HTC/Xiaomi), `com.htc.intent.action.QUICKBOOT_POWERON`, and `MY_PACKAGE_REPLACED` (Play Store updates).
227
+ 2. On boot, the receiver loads the **persisted `Config`** from SQLite (since v4.4.1 / v4.5.0 the full config is stored as `config_json`, so `httpMethod`, `queryParams`, `drivingEvents`, etc. survive).
228
+ 3. It checks `ACCESS_FINE_LOCATION` / `ACCESS_COARSE_LOCATION`, and on Android 10+ also `ACCESS_BACKGROUND_LOCATION`. If any is missing, it logs and gives up — it will **NOT** request permissions from a receiver (the OS forbids it).
229
+ 4. If permissions are OK, it calls `context.startForegroundService(...)`. The plugin's notification appears and tracking resumes with the same config the app had configured before reboot.
230
+
231
+ **Required runtime permissions** (the app must request them at least once **while it is in foreground**, before relying on `startOnBoot`):
232
+
233
+ ```ts
234
+ // Order matters — the OS dialog flow is strict on Android 11+.
235
+ await BackgroundGeolocation.requestNotificationPermission(); // Android 13+
236
+ // ACCESS_FINE_LOCATION via Cordova permission API or @capacitor/geolocation
237
+ await BackgroundGeolocation.requestBackgroundLocationPermission(); // Android 10+, user MUST pick "Allow all the time"
238
+ ```
239
+
240
+ Without **"Allow all the time"** the receiver runs but the foreground service is killed shortly after, because the OS treats the boot-launched service as "background-started" and a background start without background permission is not allowed.
241
+
242
+ **iOS:** Apple does **not** allow third-party apps to auto-start at boot. `startOnBoot: true` is silently ignored on iOS. The closest equivalent is **`significantLocationChanges`** (already implemented), which wakes the app when the device moves to a new cell tower / region — but only if the app was running at least once after the reboot. Document this expectation to your iOS users.
243
+
244
+ **Common pitfalls:**
245
+
246
+ - **OEM kills (Xiaomi MIUI, Huawei EMUI, Oppo, Vivo, OnePlus, Asus)** disable auto-start by default for non-system apps. The user must enable the app in *"Autostart"* / *"Background activity"* settings of the OEM. Use `BackgroundGeolocation.openAutoStartSettings()` to take the user directly there, and `getManufacturerHelp()` for instructions.
247
+ - **Android 12+ `ForegroundServiceStartNotAllowedException`** — if the device is in *Doze* deep-idle when it reboots, the system may block the foreground service. The plugin catches the exception and logs it; the next user-triggered `start()` (when they open the app) will succeed.
248
+ - **Doze whitelist** — `isIgnoringBatteryOptimizations()` + `requestIgnoreBatteryOptimizations()` reduce the chance of the OS putting the app on the "restricted" list after a reboot.
249
+
250
+ ```js
251
+ // Full recommended setup for "track this user across reboots"
252
+ BackgroundGeolocation.configure({
253
+ locationProvider: BackgroundGeolocation.DISTANCE_FILTER_PROVIDER,
254
+ desiredAccuracy: BackgroundGeolocation.MEDIUM_ACCURACY,
255
+ distanceFilter: 50,
256
+ startForeground: true, // mandatory for Android 8+ background tracking
257
+ notificationsEnabled: true,
258
+ notificationTitle: 'Live tracking',
259
+ notificationText: 'Your location is being shared',
260
+ startOnBoot: true, // survive reboots
261
+ stopOnTerminate: false, // keep tracking when user swipes the app away
262
+ url: 'https://my.api/locations',
263
+ syncUrl: 'https://my.api/sync'
264
+ });
265
+ ```
266
+
267
+ #### 1.3 Other main options
268
+
182
269
  **Main options:**
183
270
 
184
271
  | Option | Description |
@@ -197,14 +284,76 @@ Set your preferred provider, accuracy, intervals, and optional server URLs. All
197
284
  | `httpMethod` | **Since 3.3.0.** HTTP method for `url`. `POST` (default) `| GET | PUT | PATCH`. Use `GET` together with URL templating to deliver positions through the query string. |
198
285
  | `syncHttpMethod` | **Since 3.3.0.** HTTP method for `syncUrl`. Same values as `httpMethod`. |
199
286
  | `httpMode` / `syncMode` | **Since 3.3.0.** `batch` (default) or `single` (one HTTP request per location). `single` is required when the corresponding method is `GET`. |
200
- | `queryParams` | **Since 3.3.0.** Static placeholder values for URL/body templating (e.g. `{ device_id: 'USER_123' }`). See [HTTP transport](docs/api.md#http-transport-since-330). |
287
+ | `queryParams` | **Since 3.3.0.** Static placeholder values for URL/body templating (e.g. `{ device_id: 'USER_123' }`). See [HTTP transport](https://github.com/josuelmm/cordova-background-geolocation/blob/main/docs/api.md#http-transport-since-330). |
201
288
  | `postTemplate` / `bodyTemplate` | Object or array of properties to send. Supports `@latitude`, `@longitude`, ... and the new `{latitude}`, `{lon}`, `{timestamp_iso}`, ... placeholders on string values. `bodyTemplate` is the alias added in 3.3.0. |
202
289
  | `maxLocations` | Max locations kept in DB (default 10000). Should be > `syncThreshold`. |
203
290
 
291
+ **Diagnostics / sync (3.5+):**
292
+
293
+ | Option | Description |
294
+ |--------|-------------|
295
+ | `heartbeatInterval` | ms between `heartbeat` events. `0` (default) disables. |
296
+ | `mockLocationPolicy` | `'allow'` (default) / `'flag'` / `'drop'` — what to do with mocked locations. |
297
+
298
+ **Driver insights (4.0+):**
299
+
300
+ | Option | Description |
301
+ |--------|-------------|
302
+ | `drivingEvents.enabled` | Master switch. Default `false`. |
303
+ | `drivingEvents.speedLimit` | km/h for `speeding` event. `0` disables. |
304
+ | `drivingEvents.minMovingSpeed` | m/s threshold for "moving" (default 1.0). |
305
+ | `drivingEvents.stoppedDuration` | ms of below-threshold needed for "stopped" (default 60 000). |
306
+ | `drivingEvents.minTripSpeed` | m/s threshold for `tripStart` (default 3.0). |
307
+ | `drivingEvents.minTripDuration` | ms sustained to fire `tripStart` (default 30 000). |
308
+ | `drivingEvents.hardBrakeMps2` | m/s² threshold for `hardBrake` (default 3.5; `0` disables). |
309
+ | `drivingEvents.rapidAccelMps2` | m/s² threshold for `rapidAcceleration` (default 3.5). |
310
+ | `drivingEvents.sharpTurnDegPerSec` | deg/s for `sharpTurn` at speed ≥ 5 m/s (default 30). |
311
+ | `drivingEvents.crashImpactKmh` | km/h drop within window for GPS `possibleCrash` (default 25). |
312
+ | `drivingEvents.crashWindowMs` | window for GPS crash detection (default 2 000). |
313
+ | `drivingEvents.sensorFusion` | **4.2+.** Enable accelerometer + gyroscope. Off by default. |
314
+ | `drivingEvents.crashImpactG` | g threshold for sensor `possibleCrash` (default 3.0). |
315
+ | `drivingEvents.sensorCrashCooldownMs` | ms cooldown between sensor crash detections (default 10 000). |
316
+ | `drivingEvents.phoneUsageWindowMs` | ms of sustained jitter to fire `phoneUsageWhileDriving` (default 4 000). |
317
+ | `drivingEvents.phoneUsageCooldownMs` | ms cooldown between phone-usage events (default 60 000). |
318
+
319
+ **Battery payload (4.4+):**
320
+
321
+ | Option | Description |
322
+ |--------|-------------|
323
+ | `includeBattery` | Stamp `battery` (0-100) and `isCharging` on every fix. Default `true`. |
324
+
325
+ **Battery saving (4.5.1):**
326
+
327
+ | Option | Description |
328
+ |--------|-------------|
329
+ | `wakeLockMode` | `'none' \| 'posting' \| 'always'`. Default `'posting'`. |
330
+ | `stationaryTimeout` | ms of no movement → declare stationary (Android `DISTANCE_FILTER_PROVIDER`). Default 300 000. |
331
+ | `stationaryPollInterval` | Lazy poll interval while stationary (ms). Default 180 000. |
332
+ | `stationaryPollFast` | Aggressive poll near the stationary boundary (ms). Default 60 000. |
333
+
334
+ **Provider hardening (4.5.2):**
335
+
336
+ | Option | Description |
337
+ |--------|-------------|
338
+ | `activityConfidenceThreshold` | 0-100. Ignore STILL/ACTIVE transitions below this confidence (prevents jittery GPS start/stop). iOS normalizes Low/Med/High → 20/40/80. Default 50. Applies to `ACTIVITY_PROVIDER`. |
339
+ | `maxAcceptedAccuracy` | Maximum accepted horizontal accuracy in meters. Fixes worse than this are dropped before persist/POST/JS emission. **Off by default (`null`)** to avoid regressing existing apps. Recommended values: `100` for vehicular tracking, `500` for tolerant scenarios. All providers. |
340
+
341
+ > **Caveats v4.5.2:**
342
+ > - `maxAcceptedAccuracy` está **apagado por defecto**. Si quieres descartar fixes ruidosos (típico en GPS vehicular o indoor), seteá explícito un valor (ej. `100`).
343
+ > - **ACTIVITY_PROVIDER sin `ACTIVITY_RECOGNITION`** (Android 10+): el provider emite `PERMISSION_DENIED_ERROR` pero **degrada a tracking continuo** (no puede detectar STILL/ACTIVE). Si querés ahorro real, pedí el permiso antes de iniciar o cambiá a `DISTANCE_FILTER_PROVIDER`.
344
+ > - **`enableWatchdog`** está **apagado por defecto**. Reinicia el provider si deja de llegar `location` por ~60s (solo si `tripActive`). Útil en apps vehiculares/críticas; aumenta consumo. Recomendado `false` salvo necesidad real.
345
+ > - **`postTemplate` reemplaza el payload completo** — no hay merge con el default. Si lo defines, debes incluir manualmente `@events`, `@battery`, `@isCharging` si los necesitas. Detalle en [docs/api.md](https://github.com/josuelmm/cordova-background-geolocation/blob/main/docs/api.md#custom-post-template).
346
+ > - **`events` / `battery` / `isCharging` sobreviven la cola de sync** desde v4.5.0 (Android schema v22, iOS schema v7). Si un POST falla, esos campos persisten para `forceSync`/sync automático. Auto-migración desde versiones previas.
347
+ > - **`pendingDrivingEvents` son in-memory**: el detector almacena eventos (hardBrake, speeding, etc.) hasta anexarlos al próximo `location` (cap 20, TTL 60s). Si el proceso muere antes del próximo fix, esos eventos pueden perderse. La cola principal de ubicaciones no se afecta.
348
+ > - **`startOnBoot`** requiere: `stopOnTerminate: false` (o config persistida), `ACCESS_BACKGROUND_LOCATION` concedido (Android 10+), y que el fabricante no bloquee autostart/battery optimization. Xiaomi/Huawei/Oppo/Vivo suelen requerir desactivar manualmente la optimización de batería — usar `openBatterySettings()` / `openAutoStartSettings()` para guiar al usuario.
349
+ > - **Permisos por versión Android**: Android 10+ requiere `ACCESS_BACKGROUND_LOCATION` para tracking real en background. Android 10+ requiere `ACTIVITY_RECOGNITION` para `ACTIVITY_PROVIDER`. Android 13+ requiere `POST_NOTIFICATIONS` para la notificación foreground. Android 14+ requiere `FOREGROUND_SERVICE_LOCATION`. El plugin no fuerza permisos automáticamente; usar los helpers `requestBackgroundLocationPermission()`, `requestActivityRecognitionPermission()` y `requestNotificationPermission()`.
350
+
204
351
  **Android-only:** `notificationSyncTitle`, `notificationSyncText`, `notificationSyncCompletedText`, `notificationSyncFailedText` — texts shown in the notification while syncing (defaults in English; set for localization). `startForeground`, `notificationsEnabled`, `startOnBoot`, `stopOnTerminate`, `enableWatchdog`.
205
352
 
206
353
  **iOS-only:** `activityType`, `pauseLocationUpdates`, `saveBatteryOnBackground`, `showsBackgroundLocationIndicator` (since 3.4.0; iOS 11+, shows the blue background indicator).
207
354
 
355
+ **Full reference** (every option, with types, defaults and platform/provider hints): [`docs/api.md`](https://github.com/josuelmm/cordova-background-geolocation/blob/main/docs/api.md).
356
+
208
357
  Example (default POST + JSON):
209
358
 
210
359
  ```js
@@ -250,7 +399,7 @@ BackgroundGeolocation.configure({
250
399
  });
251
400
  ```
252
401
 
253
- > **Android runtime permissions.** With `startOnBoot: true`, the app must request `ACCESS_FINE_LOCATION` first, then `POST_NOTIFICATIONS` (Android 13+), and finally `ACCESS_BACKGROUND_LOCATION` (Android 10+, the user must pick **Allow all the time**). Without the background permission the plugin will skip the start on boot. iOS does **not** allow auto-start on device boot (Apple restriction). See [Auto-start on Android boot](docs/api.md#auto-start-on-android-boot-since-330) for the full flow.
402
+ > **Android runtime permissions.** With `startOnBoot: true`, the app must request `ACCESS_FINE_LOCATION` first, then `POST_NOTIFICATIONS` (Android 13+), and finally `ACCESS_BACKGROUND_LOCATION` (Android 10+, the user must pick **Allow all the time**). Without the background permission the plugin will skip the start on boot. iOS does **not** allow auto-start on device boot (Apple restriction). See [Auto-start on Android boot](https://github.com/josuelmm/cordova-background-geolocation/blob/main/docs/api.md#auto-start-on-android-boot-since-330) for the full flow.
254
403
 
255
404
  ### 2. Start tracking
256
405
 
@@ -298,7 +447,7 @@ When you use `syncUrl`, locations that fail to post to `url` (or that are only q
298
447
  | **`application/json`** (default) | **One POST** with a JSON **array** of all locations in the batch. |
299
448
  | **`application/x-www-form-urlencoded`** | **One POST per location** (same flat `key=value&...` as real-time to `url`). Same endpoint can handle both. |
300
449
 
301
- So: with **JSON** you get one request per batch (e.g. 100 locations in one body). With **form-urlencoded** you get one request per location (one record per POST). For headers, retries, `postTemplate` and full behaviour see [HTTP posting](docs/http_posting.md) and [API](docs/api.md).
450
+ So: with **JSON** you get one request per batch (e.g. 100 locations in one body). With **form-urlencoded** you get one request per location (one record per POST). For headers, retries, `postTemplate` and full behaviour see [HTTP posting](https://github.com/josuelmm/cordova-background-geolocation/blob/main/docs/http_posting.md) and [API](https://github.com/josuelmm/cordova-background-geolocation/blob/main/docs/api.md).
302
451
 
303
452
  You can:
304
453
 
@@ -325,27 +474,41 @@ BackgroundGeolocation.clearSync().then(function () {
325
474
  });
326
475
  ```
327
476
 
328
- More on sync (headers, retries, postTemplate): [HTTP posting](docs/http_posting.md). Full options and methods: [API](docs/api.md).
477
+ More on sync (headers, retries, postTemplate): [HTTP posting](https://github.com/josuelmm/cordova-background-geolocation/blob/main/docs/http_posting.md). Full options and methods: [API](https://github.com/josuelmm/cordova-background-geolocation/blob/main/docs/api.md).
329
478
 
330
479
  ### 6. Other methods (summary)
331
480
 
332
- | Method | Description |
333
- |--------|-------------|
334
- | `getConfig(success, fail)` | Get current configuration (merged options). |
335
- | `getLocations(success, fail)` | Get all stored locations. |
336
- | `getValidLocations(success, fail)` | Get locations not yet posted (valid only). |
337
- | `deleteLocation(id, success, fail)` | Delete one location by id. |
338
- | `deleteAllLocations(success, fail)` | Delete all stored locations. |
339
- | `getCurrentLocation(success, fail, options)` | One-shot location (e.g. timeout, maximumAge). |
340
- | `getPluginVersion(success, fail)` | Plugin version string (e.g. "3.2.0"). |
341
- | `checkStatus(success, fail)` | Service status (isRunning, authorization, etc.). |
342
- | `showAppSettings()` / `openSettings()` | Open app settings. |
343
- | `showLocationSettings()` | Open system location settings. |
344
- | `getLogEntries(limit, fromId, minLevel, success, fail)` | Debug log entries. |
345
- | `startSession(success, fail)` | Start session: clear session table and store all new locations until `clearSession()`. |
346
- | `getSessionLocations(success, fail)` | All locations in current session (restore route when reopening without internet). |
347
- | `clearSession(success, fail)` | Clear session table (call when route finished and sync OK). |
348
- | `getSessionLocationsCount(success, fail)` | Number of locations in current session. |
481
+ | Method | Since | Description |
482
+ |--------|-------|-------------|
483
+ | `getConfig(success, fail)` | 1.0 | Get current configuration (merged options). |
484
+ | `getLocations(success, fail)` | 1.0 | Get all stored locations. |
485
+ | `getValidLocations(success, fail)` | 1.0 | Get locations not yet posted (valid only). |
486
+ | `deleteLocation(id, success, fail)` | 1.0 | Delete one location by id. |
487
+ | `deleteAllLocations(success, fail)` | 1.0 | Delete all stored locations. |
488
+ | `getCurrentLocation(success, fail, options)` | 1.0 | One-shot location (e.g. timeout, maximumAge). |
489
+ | `getPluginVersion(success, fail)` | 1.0 | Plugin version string (e.g. `"4.5.1"`). |
490
+ | `checkStatus(success, fail)` | 1.0 | Service status (isRunning, authorization, etc.). |
491
+ | `showAppSettings()` / `openSettings()` | 1.0 | Open app settings. |
492
+ | `showLocationSettings()` | 1.0 | Open system location settings. |
493
+ | `getLogEntries(limit, fromId, minLevel, success, fail)` | 1.0 | Debug log entries. |
494
+ | `getPendingSyncCount(success, fail)` | 3.1 | Number of locations pending sync. |
495
+ | `forceSync(success, fail)` | 3.1 | Send pending locations immediately (ignores `syncThreshold`). |
496
+ | `clearSync(success, fail)` | 3.1 | Discard pending sync queue without sending. |
497
+ | `startSession(success, fail)` | 3.2 | Start session: clear session table and store new locations until `clearSession()`. |
498
+ | `getSessionLocations(success, fail)` | 3.2 | All locations in current session. |
499
+ | `clearSession(success, fail)` | 3.2 | Clear session table (call when route finished). |
500
+ | `getSessionLocationsCount(success, fail)` | 3.2 | Number of locations in current session. |
501
+ | `getDiagnostics(success, fail)` | 3.5 | Extended diagnostics: permissions, battery optimisation, OEM, last fix age, pending sync, iOS precise location, etc. |
502
+ | `isIgnoringBatteryOptimizations(success, fail)` | 3.6 | Android only. `true` if app is on the Doze whitelist. iOS always `true`. |
503
+ | `requestIgnoreBatteryOptimizations(success, fail)` | 3.6 | Android only. Opens the system dialog to add the app to the whitelist. |
504
+ | `openBatterySettings(success, fail)` | 3.6 | Android only. Opens the battery-related settings screen for this app. |
505
+ | `openAutoStartSettings(success, fail)` | 3.6 | Android only. Opens the OEM-specific auto-start screen (Xiaomi/Huawei/Oppo/Vivo/OnePlus/Asus). |
506
+ | `getManufacturerHelp(success, fail)` | 3.6 | Returns `{ manufacturer, steps[] }` with OEM-specific guidance text. |
507
+ | `triggerSOS(payload?, success, fail)` | 4.0 | Emit a single `sos` event with the latest location plus your payload. Host app handles actual SOS workflow. |
508
+ | `requestBackgroundLocationPermission(success, fail)` | 4.5 | Android 10+. Request `ACCESS_BACKGROUND_LOCATION`. iOS / older Android resolve `{ granted: true, notRequired: true }`. |
509
+ | `requestActivityRecognitionPermission(success, fail)` | 4.5 | Android 10+. Request `ACTIVITY_RECOGNITION`. |
510
+ | `requestNotificationPermission(success, fail)` | 4.5 | Android 13+. Request `POST_NOTIFICATIONS`. |
511
+ | `headlessTask(task)` | 1.0 | **Android only.** Run JS when app is terminated and `stopOnTerminate: false`. iOS no-op. |
349
512
 
350
513
  All methods return a **Promise** if you omit the `success` / `fail` callbacks.
351
514
 
@@ -353,6 +516,8 @@ All methods return a **Promise** if you omit the `success` / `fail` callbacks.
353
516
 
354
517
  Subscribe with `BackgroundGeolocation.on(eventName, callback)`. Unsubscribe with the returned object’s `remove()` or by calling `removeAllListeners(eventName)`.
355
518
 
519
+ #### Core (1.0+)
520
+
356
521
  | Event | Payload | When |
357
522
  |-------|---------|------|
358
523
  | `location` | Location object | New location (foreground/background). |
@@ -366,7 +531,99 @@ Subscribe with `BackgroundGeolocation.on(eventName, callback)`. Unsubscribe with
366
531
  | `http_authorization` | — | Server returned 401; refresh token and reconfigure headers. |
367
532
  | `abort_requested` | — | Server returned 285 (updates not required). |
368
533
 
369
- Full event payloads and options: [Events](docs/events.md). Full API (all options, all methods): [API](docs/api.md).
534
+ #### Diagnostics + Sync (3.5+)
535
+
536
+ | Event | Payload | When |
537
+ |-------|---------|------|
538
+ | `heartbeat` | `Location` or `void` | Periodic heartbeat at `heartbeatInterval` ms. Disabled when `heartbeatInterval = 0`. |
539
+ | `syncStart` | — | Background sync POST started. |
540
+ | `syncProgress` | `number` (0-100) | Sync upload progress. |
541
+ | `syncSuccess` | `{ sent: number }` | Sync completed, N locations uploaded. |
542
+ | `syncError` | `{ httpStatus, message }` | Sync failed (network or server). |
543
+
544
+ #### Driver insights (4.0+)
545
+
546
+ | Event | Payload | When |
547
+ |-------|---------|------|
548
+ | `tripStart` | `Location` | Sustained speed ≥ `minTripSpeed` for `minTripDuration` ms. |
549
+ | `tripEnd` | `{ location, distance, durationMs }` | Stationary detected during active trip. |
550
+ | `moving` | `Location` | Speed crossed `minMovingSpeed` upward. |
551
+ | `stopped` | `Location` | `stoppedDuration` ms below `minMovingSpeed`. |
552
+ | `speeding` | `{ location, speedKmh, limitKmh }` | Above `drivingEvents.speedLimit` (rearms on drop). |
553
+ | `providerChange` | `{ provider }` | Location provider changed (gps/network/fused). |
554
+ | `sos` | `{ location, ...payload }` | `BackgroundGeolocation.triggerSOS(payload)` invoked. |
555
+
556
+ #### Driving events — GPS-derived (4.1+) / sensor fusion (4.2+)
557
+
558
+ | Event | Payload | When |
559
+ |-------|---------|------|
560
+ | `hardBrake` | `{ location, value }` | Δspeed/Δt ≤ −`hardBrakeMps2` during active trip. `value` is m/s² (negative). |
561
+ | `rapidAcceleration` | `{ location, value }` | Δspeed/Δt ≥ `rapidAccelMps2`. `value` is m/s² (positive). |
562
+ | `sharpTurn` | `{ location, value }` | Bearing change rate ≥ `sharpTurnDegPerSec` and speed ≥ 5 m/s. `value` is deg/s. |
563
+ | `possibleCrash` | `{ location, value, source }` | GPS heuristic (`source: 'gps'`, `value`: km/h drop) **or** sensor impact (`source: 'sensor'`, `value`: g). Always confirm with user before notifying contacts. |
564
+ | `phoneUsageWhileDriving` | `Location` | Sustained device interaction during active trip with screen on. Requires `drivingEvents.sensorFusion: true`. |
565
+
566
+ Full event payloads and options: [Events](https://github.com/josuelmm/cordova-background-geolocation/blob/main/docs/events.md). Full API (all options, all methods): [API](https://github.com/josuelmm/cordova-background-geolocation/blob/main/docs/api.md).
567
+
568
+ ### New in 4.5.1
569
+
570
+ Stability + battery optimization release. No new features — only fixes that make the plugin safe for long-term production.
571
+
572
+ - **`wakeLockMode: 'none' | 'posting' | 'always'`** (default `'posting'`). Replaces the previous always-on `PARTIAL_WAKE_LOCK`. `'posting'` acquires a bounded 30 s lock around each fix (SQLite + HTTP POST); `'none'` never acquires; `'always'` is the legacy behaviour for fleet/emergency apps.
573
+ - **Watchdog moving-only** — `enableWatchdog: true` no longer restarts the provider when the device is intentionally stationary. Saves real battery during parking/idle.
574
+ - **Stationary detection configurable** — `stationaryTimeout`, `stationaryPollInterval`, `stationaryPollFast` (Android `DISTANCE_FILTER_PROVIDER`). Defaults: 300 000 / 180 000 / 60 000 ms.
575
+ - **Critical persistence fixes**: `maxLocations` recycle no longer mixes old `events_json`/`battery_level`/`is_charging` into new rows; iOS sync no longer marks rows `Deleted` before the upload finishes (was losing the whole queue on network drop). iOS rescues `SyncPending` rows stale > 15 min after a crash.
576
+ - **iOS race condition fixed**: `MAURLocationMapper._location` was a file-scope global → real-time post + background sync running concurrently produced mixed fixes. Now per-instance ivar.
577
+ - **`locationTransform`**: events / battery / charging now survive transforms that return a new instance (both platforms).
578
+
579
+ ### New in 4.5.0
580
+
581
+ - **Driving events, battery and isCharging now survive the sync queue.** Android DB v22 + iOS DB v7 add `events_json` / `battery_level` / `is_charging` columns on `location`. When a real-time POST fails and the location enters SQLite, those fields travel with it to the backend on the next sync.
582
+ - **iOS config persistence parity** — `MAURConfig` now serialises post-3.2 keys (`httpMethod`, `queryParams`, `drivingEvents`, `includeBattery`, etc.) to a `config_json` blob, matching Android v4.4.1.
583
+ - **Runtime permission helpers** (Android): `requestBackgroundLocationPermission()`, `requestActivityRecognitionPermission()`, `requestNotificationPermission()`. iOS / older Android resolve `{ granted: true, notRequired: true }`.
584
+ - **iOS background sync cleanup**: rows that were uploaded successfully are now removed from SQLite (the previous code re-uploaded them every cycle).
585
+
586
+ ### New in 4.4.0
587
+
588
+ Cada location enviada al backend incluye `battery` (0-100) y `isCharging` automáticamente. Sin dependencias externas (no necesitas `cordova-plugin-battery-status`).
589
+
590
+ ```json
591
+ {
592
+ "latitude": 40.4168, "longitude": -3.7038, "speed": 8.2,
593
+ "battery": 78, "isCharging": false
594
+ }
595
+ ```
596
+
597
+ Default ON. Opt-out: `configure({ includeBattery: false })`. Con templates custom usa los placeholders `'@battery'` y `'@isCharging'`.
598
+
599
+ ### New in 4.3.0
600
+
601
+ Driving events ahora se **anexan al location** que se envía al backend, en un atributo `events`:
602
+
603
+ ```json
604
+ {
605
+ "latitude": 40.4168,
606
+ "longitude": -3.7038,
607
+ "time": 1730000000000,
608
+ "speed": 8.2,
609
+ "events": [
610
+ { "type": "hardBrake", "value": -4.1, "time": 1730000000000 }
611
+ ]
612
+ }
613
+ ```
614
+
615
+ Tipos: `moving`, `stopped`, `tripStart`, `tripEnd`, `speeding`, `providerChange`, `hardBrake`, `rapidAcceleration`, `sharpTurn`, `possibleCrash`, `phoneUsageWhileDriving`. La emisión por JS sigue funcionando idéntica (no rompe Opción A).
616
+
617
+ Desde v4.5.0, `events`, `battery` e `isCharging` se persisten en la cola de sync (Android DB v22, iOS DB v7) y sobreviven a POST fallido → SQLite/Core Data → background sync.
618
+
619
+ Si usas `postTemplate`/`bodyTemplate` custom, añade el placeholder `'@events'` para incluirlos:
620
+
621
+ ```js
622
+ postTemplate: {
623
+ lat: '@latitude', lon: '@longitude', t: '@time',
624
+ events: '@events'
625
+ }
626
+ ```
370
627
 
371
628
  ### New in 4.2.2
372
629
 
@@ -402,7 +659,7 @@ BackgroundGeolocation.on('phoneUsageWhileDriving', (location) => {
402
659
  });
403
660
  ```
404
661
 
405
- Full reference (all thresholds, when to enable, iOS screen-on caveat): [docs/api.md → Driver insights](docs/api.md#driver-insights-since-400).
662
+ Full reference (all thresholds, when to enable, iOS screen-on caveat): [docs/api.md → Driver insights](https://github.com/josuelmm/cordova-background-geolocation/blob/main/docs/api.md#driver-insights-since-400).
406
663
 
407
664
  ### New in 4.1.0
408
665
 
@@ -431,7 +688,7 @@ Full reference (all thresholds, when to enable, iOS screen-on caveat): [docs/api
431
688
 
432
689
  ### New in 3.5.0
433
690
 
434
- - **`getDiagnostics()` (Phase 4).** New extended diagnostics method that helps you debug "tracking is not running" in production. Returns permissions (`fineLocationGranted`, `coarseLocationGranted`, `backgroundLocationGranted`, `notificationPermissionGranted`, `activityRecognitionGranted`), battery optimisation state (`batteryOptimizationIgnored`), OEM manufacturer (`manufacturer`), last-fix timestamp, pending sync count, declared `foregroundServiceType` (Android), and `preciseLocationEnabled`, `backgroundRefreshStatus`, `lowPowerModeEnabled`, `motionPermissionStatus` (iOS). Use it to surface actionable hints to users like "Allow all the time" or "Disable battery optimisation". See [getDiagnostics](docs/api.md#getdiagnosticssuccess-fail).
691
+ - **`getDiagnostics()` (Phase 4).** New extended diagnostics method that helps you debug "tracking is not running" in production. Returns permissions (`fineLocationGranted`, `coarseLocationGranted`, `backgroundLocationGranted`, `notificationPermissionGranted`, `activityRecognitionGranted`), battery optimisation state (`batteryOptimizationIgnored`), OEM manufacturer (`manufacturer`), last-fix timestamp, pending sync count, declared `foregroundServiceType` (Android), and `preciseLocationEnabled`, `backgroundRefreshStatus`, `lowPowerModeEnabled`, `motionPermissionStatus` (iOS). Use it to surface actionable hints to users like "Allow all the time" or "Disable battery optimisation". See [getDiagnostics](https://github.com/josuelmm/cordova-background-geolocation/blob/main/docs/api.md#getdiagnosticssuccess-fail).
435
692
  - **`mockLocationPolicy: 'allow' | 'flag' | 'drop'`** — policy for mocked locations. Detection (`isFromMockProvider` Android, `simulated` iOS) was already present; this option controls what to do with those samples. Recommended for anti-fraud: `'flag'` (keep them but tagged) or `'drop'` (discard).
436
693
  - **`heartbeatInterval`** option plus events `heartbeat`, `syncStart`, `syncProgress`, `syncSuccess`, `syncError` are all wired end-to-end with native emission on Android and iOS. Subscribe via `BackgroundGeolocation.on('heartbeat', cb)` etc.
437
694
  - The Angular service exposes `getDiagnostics()` directly.
@@ -446,7 +703,7 @@ Full reference (all thresholds, when to enable, iOS screen-on caveat): [docs/api
446
703
  ### New in 3.3.0
447
704
 
448
705
  - **Auto-start Android (Phase 1).** The plugin's boot receiver now also handles `QUICKBOOT_POWERON` (HTC, MIUI / Xiaomi), `com.htc.intent.action.QUICKBOOT_POWERON`, and `MY_PACKAGE_REPLACED` (the service relaunches after a Play Store update). Added `ACCESS_BACKGROUND_LOCATION` to the manifest with runtime validation on Android 10+. `ForegroundServiceStartNotAllowedException` (Android 12+) is caught with clear logging — WorkManager is **not** used as a fallback for tracking. The `foregroundServiceType` is now `"location"` only (dropped `dataSync`); the runtime type is read dynamically from the merged manifest. `<uses-library org.apache.http.legacy>` and `useLibrary 'org.apache.http.legacy'` are removed (the plugin uses `HttpURLConnection`). `jcenter()` → `mavenCentral()`.
449
- - **Backend-agnostic HTTP transport (Phase 2).** New `httpMethod`, `syncHttpMethod`, `httpMode`, `syncMode`, `queryParams`, `headers` (alias of `httpHeaders`), `bodyTemplate` (alias of `postTemplate`). URL templating with `{latitude}`, `{longitude}`, `{lat}`, `{lon}`, `{time}`, `{timestamp}`, `{timestamp_iso}`, `{speed}`, `{altitude}`, `{bearing}`, `{accuracy}`, `{provider}` and any keys from `queryParams`. The plugin no longer hardcodes `POST` on Android (`HttpPostService`) or iOS (`MAURPostLocationTask`, `MAURBackgroundSync`). Compatibility is fully preserved — apps that only set `url` + `httpHeaders` + `postTemplate` keep working unchanged. See [HTTP transport](docs/api.md#http-transport-since-330) for backend examples (REST, GET single, form-urlencoded, Firebase, n8n).
706
+ - **Backend-agnostic HTTP transport (Phase 2).** New `httpMethod`, `syncHttpMethod`, `httpMode`, `syncMode`, `queryParams`, `headers` (alias of `httpHeaders`), `bodyTemplate` (alias of `postTemplate`). URL templating with `{latitude}`, `{longitude}`, `{lat}`, `{lon}`, `{time}`, `{timestamp}`, `{timestamp_iso}`, `{speed}`, `{altitude}`, `{bearing}`, `{accuracy}`, `{provider}` and any keys from `queryParams`. The plugin no longer hardcodes `POST` on Android (`HttpPostService`) or iOS (`MAURPostLocationTask`, `MAURBackgroundSync`). Compatibility is fully preserved — apps that only set `url` + `httpHeaders` + `postTemplate` keep working unchanged. See [HTTP transport](https://github.com/josuelmm/cordova-background-geolocation/blob/main/docs/api.md#http-transport-since-330) for backend examples (REST, GET single, form-urlencoded, Firebase, n8n).
450
707
  - **Engines:** `cordova-android >= 12.0.0` is now the minimum.
451
708
 
452
709
  ### New in 3.2.0
@@ -460,7 +717,7 @@ Full reference (all thresholds, when to enable, iOS screen-on caveat): [docs/api
460
717
 
461
718
  ### New in 3.1.1
462
719
 
463
- - **Browser / `ng serve` builds** — The plugin can now be bundled by webpack without "Can't resolve 'cordova/exec'" or "Can't resolve 'cordova/channel'". The package ships stub modules and a `browser` field so `ng serve` and browser builds succeed; on device/emulator the stubs delegate to the real Cordova API. See [docs/angular.md](docs/angular.md#build-ng-serve--browser).
720
+ - **Browser / `ng serve` builds** — The plugin can now be bundled by webpack without "Can't resolve 'cordova/exec'" or "Can't resolve 'cordova/channel'". The package ships stub modules and a `browser` field so `ng serve` and browser builds succeed; on device/emulator the stubs delegate to the real Cordova API. See [docs/angular.md](https://github.com/josuelmm/cordova-background-geolocation/blob/main/docs/angular.md#build-ng-serve--browser).
464
721
 
465
722
  ### New in 3.1.0
466
723
 
@@ -473,7 +730,7 @@ Full reference (all thresholds, when to enable, iOS screen-on caveat): [docs/api
473
730
 
474
731
  ---
475
732
 
476
- More (stationary, activity, headless task, Angular) is in the [documentation](https://josuelmm.github.io/cordova-background-geolocation/). For **Angular** (service, methods, events), see [docs/angular.md](docs/angular.md).
733
+ More (stationary, activity, headless task, Angular) is in the [documentation](https://josuelmm.github.io/cordova-background-geolocation/). For **Angular** (service, methods, events), see [docs/angular.md](https://github.com/josuelmm/cordova-background-geolocation/blob/main/docs/angular.md).
477
734
 
478
735
  ---
479
736
 
@@ -516,13 +773,13 @@ export class MyService {
516
773
  }
517
774
  ```
518
775
 
519
- **You must import `BackgroundGeolocationModule`** in your `AppModule` (or feature module) so the service is provided and AOT builds work. Then inject `BackgroundGeolocationService` as in the example above. See [docs/angular.md](docs/angular.md) for the full snippet.
776
+ **You must import `BackgroundGeolocationModule`** in your `AppModule` (or feature module) so the service is provided and AOT builds work. Then inject `BackgroundGeolocationService` as in the example above. See [docs/angular.md](https://github.com/josuelmm/cordova-background-geolocation/blob/main/docs/angular.md) for the full snippet.
520
777
 
521
- **`ng serve` / browser:** From 3.1.1 the plugin includes browser stubs so `ng serve` and web builds complete without "Can't resolve 'cordova/exec'" — see [docs/angular.md](docs/angular.md#build-ng-serve--browser).
778
+ **`ng serve` / browser:** From 3.1.1 the plugin includes browser stubs so `ng serve` and web builds complete without "Can't resolve 'cordova/exec'" — see [docs/angular.md](https://github.com/josuelmm/cordova-background-geolocation/blob/main/docs/angular.md#build-ng-serve--browser).
522
779
 
523
- **Lazy-loaded pages:** If you see **NG0202** or *"dependency at index N is invalid"* when opening a page that injects this service, use an app-defined token and inject by that token (the plugin token can be undefined in the lazy chunk). See [docs/angular.md](docs/angular.md) (Lazy-loaded modules).
780
+ **Lazy-loaded pages:** If you see **NG0202** or *"dependency at index N is invalid"* when opening a page that injects this service, use an app-defined token and inject by that token (the plugin token can be undefined in the lazy chunk). See [docs/angular.md](https://github.com/josuelmm/cordova-background-geolocation/blob/main/docs/angular.md) (Lazy-loaded modules).
524
781
 
525
- **Migrating from @awesome-cordova-plugins/background-geolocation:** there you inject a class named `BackgroundGeolocation`. In this package, `BackgroundGeolocation` is the **global plugin object**, not an injectable class. Use `BackgroundGeolocationService` instead (same API). See [docs/angular.md](docs/angular.md) for details.
782
+ **Migrating from @awesome-cordova-plugins/background-geolocation:** there you inject a class named `BackgroundGeolocation`. In this package, `BackgroundGeolocation` is the **global plugin object**, not an injectable class. Use `BackgroundGeolocationService` instead (same API). See [docs/angular.md](https://github.com/josuelmm/cordova-background-geolocation/blob/main/docs/angular.md) for details.
526
783
 
527
784
  ### Summary
528
785
 
@@ -543,8 +800,16 @@ No extra wrapper (e.g. Awesome Cordova Plugins) is required.
543
800
  | 2.x | ≥ 10.0.0 | ≥ 10.0.0 | ≥ 6.0.0 |
544
801
  | 3.0.x – 3.2.x | ≥ 10.0.0 | ≥ 10.0.0 | ≥ 6.0.0 |
545
802
  | 3.3.x – 4.1.x | ≥ 10.0.0 | ≥ 12.0.0 | ≥ 6.2.0 |
803
+ | 4.2.x – 4.5.x | ≥ 10.0.0 | ≥ 12.0.0 | ≥ 6.2.0 |
546
804
 
547
805
  > 3.3.0+: `cordova-android >= 12` is required for `targetSdk 34+` and the modernised foreground-service handling. The new iOS APIs (`showsBackgroundLocationIndicator` iOS 11+, `locationManagerDidChangeAuthorization:` iOS 14+) are gated by runtime `@available` checks, so older iOS versions still link and run.
806
+ >
807
+ > 4.5.0+: SQLite schemas bumped (Android v22, iOS v7) to persist `events`, `battery`, `isCharging` across the sync queue. Upgrades from any earlier version auto-migrate.
808
+ >
809
+ > 4.5.2+ — **Google Play Services matrix (Android)**:
810
+ > - `RAW_PROVIDER` — no requiere Play Services (usa OS LocationManager). Funciona en Huawei/HMS, AOSP, China ROMs.
811
+ > - `DISTANCE_FILTER_PROVIDER` — **híbrido**: usa `FusedLocationProviderClient` cuando hay Play Services, fallback automático a `LocationManager` cuando no. Funciona en todos los Android.
812
+ > - `ACTIVITY_PROVIDER` — **requiere Play Services** (depende de `ActivityRecognitionClient`, sin equivalente OS). En dispositivos sin Play Services usar `DISTANCE_FILTER_PROVIDER` o `RAW_PROVIDER`.
548
813
 
549
814
  ---
550
815
 
@@ -554,90 +819,16 @@ This README is the main entry point. For more detail, edge cases and examples us
554
819
 
555
820
  | Doc | What you'll find |
556
821
  |-----|------------------|
557
- | **[API reference](docs/api.md)** | Every `configure` option, every method (`configure`, `start`, `stop`, `getPendingSyncCount`, `forceSync`, `clearSync`, `startSession`, `getSessionLocations`, `clearSession`, `getSessionLocationsCount`, `getConfig`, `getLocations`, etc.), TypeScript types. Also covers the **HTTP transport (3.3.0)** and **auto-start on Android boot (3.3.0)**. |
558
- | **[HTTP transport (3.3.0)](docs/http-transport.md)** | `httpMethod`, `httpMode`, URL templating, `bodyTemplate`, `queryParams`, examples for REST, GET single, form-urlencoded, Firebase, n8n, Traccar. |
559
- | **[Auto-start on boot (3.3.0)](docs/auto-start.md)** | Android receiver actions, `ACCESS_BACKGROUND_LOCATION` runtime flow, OEM caveats, iOS limitation. |
560
- | **[Traccar integration example](docs/traccar.md)** | Optional backend: how to deliver positions to Traccar (or Firebase, n8n, custom REST) via the HTTP transport. The plugin is backend-agnostic. |
561
- | **[Location modernization (3.4.0)](docs/location-modernization.md)** | What was modernised in Phase 3 (LocationRequest.Builder, NSURLSession, iOS 14+ auth callback) and what is still legacy. |
562
- | **[Roadmap](docs/ROADMAP.md)** | Phases 1–6, what's released, what's next. |
563
- | **[HTTP posting](docs/http_posting.md)** | `url` vs `syncUrl`, Content-Type (JSON = one POST with array; form-urlencoded = one POST per location), headers, retries, `postTemplate`, sync behaviour. |
564
- | **[Events](docs/events.md)** | All events (`location`, `error`, `stationary`, `activity`, `http_authorization`, etc.) and payloads. |
565
- | **[Angular / Ionic](docs/angular.md)** | Injectable service, module, lazy-loaded modules and token "must be defined", `ng serve` / browser build. |
566
- | **[Example](docs/example.md)** | Full example with events and sync. |
567
- | **[CHANGELOG](CHANGELOG.md)** | Version history. |
568
-
569
- This project is based on [@mauron85/cordova-plugin-background-geolocation](https://github.com/mauron85/cordova-plugin-background-geolocation) and the original by [christocracy](https://github.com/christocracy). Maintained at [josuelmm/cordova-background-geolocation](https://github.com/josuelmm/cordova-background-geolocation). Issues and PRs welcome.
570
-
571
- ---
572
-
573
- ## Licence
574
-
575
- [Apache License](http://www.apache.org/licenses/LICENSE-2.0)
576
-
577
- Copyright (c) 2013 Christopher Scott, Transistor Software
578
-
579
- Permission is hereby granted, free of charge, to any person obtaining a copy
580
- of this software and associated documentation files (the "Software"), to deal
581
- in the Software without restriction, including without limitation the rights
582
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
583
- copies of the Software, and to permit persons to whom the Software is
584
- furnished to do so, subject to the following conditions:
585
-
586
- The above copyright notice and this permission notice shall be included in
587
- all copies or substantial portions of the Software.
588
-
589
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
590
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
591
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
592
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
593
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
594
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
595
- THE SOFTWARE.
596
- return this.bg.on('location', (loc: BackgroundGeolocationResponse) => console.log(loc));
597
- // subscription.unsubscribe() when done
598
- }
599
- }
600
- ```
601
-
602
- **You must import `BackgroundGeolocationModule`** in your `AppModule` (or feature module) so the service is provided and AOT builds work. Then inject `BackgroundGeolocationService` as in the example above. See [docs/angular.md](docs/angular.md) for the full snippet.
603
-
604
- **`ng serve` / browser:** From 3.1.1 the plugin includes browser stubs so `ng serve` and web builds complete without "Can't resolve 'cordova/exec'" — see [docs/angular.md](docs/angular.md#build-ng-serve--browser).
605
-
606
- **Lazy-loaded pages:** If you see **NG0202** or *"dependency at index N is invalid"* when opening a page that injects this service, use an app-defined token and inject by that token (the plugin token can be undefined in the lazy chunk). See [docs/angular.md](docs/angular.md) (Lazy-loaded modules).
607
-
608
- **Migrating from @awesome-cordova-plugins/background-geolocation:** there you inject a class named `BackgroundGeolocation`. In this package, `BackgroundGeolocation` is the **global plugin object**, not an injectable class. Use `BackgroundGeolocationService` instead (same API). See [docs/angular.md](docs/angular.md) for details.
609
-
610
- ### Summary
611
-
612
- | Use case | What to do |
613
- |-----------------------|------------|
614
- | **Without Angular** | Use global `BackgroundGeolocation` after `deviceready`. Types: main package or Awesome-style aliases (see [TypeScript imports](#typescript-imports) above). |
615
- | **With Angular** | Import from `@josuelmm/cordova-background-geolocation/angular`: add `BackgroundGeolocationModule` to your module `imports`, then inject `BackgroundGeolocationService`. Do **not** inject the global `BackgroundGeolocation`. |
616
-
617
- No extra wrapper (e.g. Awesome Cordova Plugins) is required.
618
-
619
- ---
620
-
621
- ## Compatibility
622
-
623
- | Plugin version | Cordova CLI | Cordova Android | Cordova iOS |
624
- |----------------|-------------|-----------------|-------------|
625
- | 1.x | ≥ 8.0.0 | ≥ 8.0.0 | ≥ 6.0.0 |
626
- | 2.x | ≥ 10.0.0 | ≥ 10.0.0 | ≥ 6.0.0 |
627
-
628
- ---
629
-
630
- ## Documentation and changelog
631
-
632
- This README is the main entry point. For more detail, edge cases and examples use the docs below (and the [online documentation](https://josuelmm.github.io/cordova-background-geolocation/)).
633
-
634
- | Doc | What you’ll find |
635
- |-----|------------------|
636
- | **[API reference](docs/api.md)** | Every `configure` option, every method (`configure`, `start`, `stop`, `getPendingSyncCount`, `forceSync`, `clearSync`, `startSession`, `getSessionLocations`, `clearSession`, `getSessionLocationsCount`, `getConfig`, `getLocations`, etc.), TypeScript types. |
637
- | **[HTTP posting](docs/http_posting.md)** | `url` vs `syncUrl`, Content-Type (JSON = one POST with array; form-urlencoded = one POST per location), headers, retries, `postTemplate`, sync behaviour. |
638
- | **[Events](docs/events.md)** | All events (`location`, `error`, `stationary`, `activity`, `http_authorization`, etc.) and payloads. |
639
- | **[Angular / Ionic](docs/angular.md)** | Injectable service, module, lazy-loaded modules and token “must be defined”, `ng serve` / browser build. |
640
- | **[Example](docs/example.md)** | Full example with events and sync. |
822
+ | **[API reference](https://github.com/josuelmm/cordova-background-geolocation/blob/main/docs/api.md)** | Every `configure` option, every method (`configure`, `start`, `stop`, `getPendingSyncCount`, `forceSync`, `clearSync`, `startSession`, `getSessionLocations`, `clearSession`, `getSessionLocationsCount`, `getConfig`, `getLocations`, etc.), TypeScript types. Also covers the **HTTP transport (3.3.0)** and **auto-start on Android boot (3.3.0)**. |
823
+ | **[HTTP transport (3.3.0)](https://github.com/josuelmm/cordova-background-geolocation/blob/main/docs/http-transport.md)** | `httpMethod`, `httpMode`, URL templating, `bodyTemplate`, `queryParams`, examples for REST, GET single, form-urlencoded, Firebase, n8n, Traccar. |
824
+ | **[Auto-start on boot (3.3.0)](https://github.com/josuelmm/cordova-background-geolocation/blob/main/docs/auto-start.md)** | Android receiver actions, `ACCESS_BACKGROUND_LOCATION` runtime flow, OEM caveats, iOS limitation. |
825
+ | **[Traccar integration example](https://github.com/josuelmm/cordova-background-geolocation/blob/main/docs/traccar.md)** | Optional backend: how to deliver positions to Traccar (or Firebase, n8n, custom REST) via the HTTP transport. The plugin is backend-agnostic. |
826
+ | **[Location modernization (3.4.0)](https://github.com/josuelmm/cordova-background-geolocation/blob/main/docs/location-modernization.md)** | What was modernised in Phase 3 (LocationRequest.Builder, NSURLSession, iOS 14+ auth callback) and what is still legacy. |
827
+ | **[Roadmap](https://github.com/josuelmm/cordova-background-geolocation/blob/main/docs/ROADMAP.md)** | Phases 1–6, what's released, what's next. |
828
+ | **[HTTP posting](https://github.com/josuelmm/cordova-background-geolocation/blob/main/docs/http_posting.md)** | `url` vs `syncUrl`, Content-Type (JSON = one POST with array; form-urlencoded = one POST per location), headers, retries, `postTemplate`, sync behaviour. |
829
+ | **[Events](https://github.com/josuelmm/cordova-background-geolocation/blob/main/docs/events.md)** | All events (`location`, `error`, `stationary`, `activity`, `http_authorization`, etc.) and payloads. |
830
+ | **[Angular / Ionic](https://github.com/josuelmm/cordova-background-geolocation/blob/main/docs/angular.md)** | Injectable service, module, lazy-loaded modules and token "must be defined", `ng serve` / browser build. |
831
+ | **[Example](https://github.com/josuelmm/cordova-background-geolocation/blob/main/docs/example.md)** | Full example with events and sync. |
641
832
  | **[CHANGELOG](CHANGELOG.md)** | Version history. |
642
833
 
643
834
  This project is based on [@mauron85/cordova-plugin-background-geolocation](https://github.com/mauron85/cordova-plugin-background-geolocation) and the original by [christocracy](https://github.com/christocracy). Maintained at [josuelmm/cordova-background-geolocation](https://github.com/josuelmm/cordova-background-geolocation). Issues and PRs welcome.
@@ -181,6 +181,30 @@ public class ConfigMapper {
181
181
  if (jObject.has("showDistance")) {
182
182
  config.setShowDistance(jObject.getBoolean("showDistance"));
183
183
  }
184
+ // v4.4: opt-out for battery snapshot in payload.
185
+ if (jObject.has("includeBattery")) {
186
+ config.setIncludeBattery(jObject.getBoolean("includeBattery"));
187
+ }
188
+ // v4.5.1: battery-saving knobs.
189
+ if (jObject.has("wakeLockMode") && !jObject.isNull("wakeLockMode")) {
190
+ config.setWakeLockMode(jObject.getString("wakeLockMode"));
191
+ }
192
+ if (jObject.has("stationaryTimeout") && !jObject.isNull("stationaryTimeout")) {
193
+ config.setStationaryTimeout(jObject.getInt("stationaryTimeout"));
194
+ }
195
+ if (jObject.has("stationaryPollInterval") && !jObject.isNull("stationaryPollInterval")) {
196
+ config.setStationaryPollInterval(jObject.getInt("stationaryPollInterval"));
197
+ }
198
+ if (jObject.has("stationaryPollFast") && !jObject.isNull("stationaryPollFast")) {
199
+ config.setStationaryPollFast(jObject.getInt("stationaryPollFast"));
200
+ }
201
+ // v4.5.2: provider hardening
202
+ if (jObject.has("activityConfidenceThreshold") && !jObject.isNull("activityConfidenceThreshold")) {
203
+ config.setActivityConfidenceThreshold(jObject.getInt("activityConfidenceThreshold"));
204
+ }
205
+ if (jObject.has("maxAcceptedAccuracy") && !jObject.isNull("maxAcceptedAccuracy")) {
206
+ config.setMaxAcceptedAccuracy((float) jObject.getDouble("maxAcceptedAccuracy"));
207
+ }
184
208
 
185
209
  return config;
186
210
  }
@@ -264,6 +288,16 @@ public class ConfigMapper {
264
288
  deJson.put("phoneUsageCooldownMs", de.phoneUsageCooldownMs);
265
289
  json.put("drivingEvents", deJson);
266
290
  }
291
+ // v4.4 battery
292
+ json.put("includeBattery", config.getIncludeBattery() != null ? config.getIncludeBattery() : true);
293
+ // v4.5.1 battery-saving knobs
294
+ json.put("wakeLockMode", config.getWakeLockMode() != null ? config.getWakeLockMode() : "posting");
295
+ json.put("stationaryTimeout", config.getStationaryTimeout());
296
+ json.put("stationaryPollInterval", config.getStationaryPollInterval());
297
+ json.put("stationaryPollFast", config.getStationaryPollFast());
298
+ // v4.5.2 provider hardening
299
+ json.put("activityConfidenceThreshold", config.getActivityConfidenceThreshold());
300
+ json.put("maxAcceptedAccuracy", config.getMaxAcceptedAccuracy());
267
301
 
268
302
  return json;
269
303
  }