@josuelmm/cordova-background-geolocation 3.2.0 → 4.2.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 (51) hide show
  1. package/.npmignore +4 -0
  2. package/CHANGELOG.md +290 -0
  3. package/CLAUDE.md +56 -0
  4. package/HISTORY.md +125 -0
  5. package/README.md +189 -4
  6. package/android/CDVBackgroundGeolocation/src/main/java/com/marianhello/bgloc/cordova/ConfigMapper.java +90 -0
  7. package/android/CDVBackgroundGeolocation/src/main/java/com/tenforwardconsulting/bgloc/cordova/BackgroundGeolocationPlugin.java +310 -1
  8. package/android/common/src/main/java/com/marianhello/bgloc/BackgroundGeolocationFacade.java +127 -0
  9. package/android/common/src/main/java/com/marianhello/bgloc/BootCompletedReceiver.java +27 -11
  10. package/android/common/src/main/java/com/marianhello/bgloc/Config.java +268 -0
  11. package/android/common/src/main/java/com/marianhello/bgloc/HttpPostService.java +86 -26
  12. package/android/common/src/main/java/com/marianhello/bgloc/PluginDelegate.java +26 -0
  13. package/android/common/src/main/java/com/marianhello/bgloc/PostLocationTask.java +42 -5
  14. package/android/common/src/main/java/com/marianhello/bgloc/driving/DrivingEventsDetector.java +265 -0
  15. package/android/common/src/main/java/com/marianhello/bgloc/http/UrlTemplateResolver.java +115 -0
  16. package/android/common/src/main/java/com/marianhello/bgloc/oem/BatteryOemHelper.java +214 -0
  17. package/android/common/src/main/java/com/marianhello/bgloc/provider/ActivityRecognitionLocationProvider.java +13 -9
  18. package/android/common/src/main/java/com/marianhello/bgloc/provider/DistanceFilterLocationProvider.java +29 -40
  19. package/android/common/src/main/java/com/marianhello/bgloc/provider/RawLocationProvider.java +14 -34
  20. package/android/common/src/main/java/com/marianhello/bgloc/sensor/SensorFusionDetector.java +199 -0
  21. package/android/common/src/main/java/com/marianhello/bgloc/service/LocationServiceImpl.java +305 -6
  22. package/android/common/src/main/java/com/marianhello/bgloc/service/LocationServiceProxy.java +14 -2
  23. package/android/common/src/main/java/com/marianhello/bgloc/sync/SyncAdapter.java +50 -3
  24. package/android/dependencies.gradle +0 -3
  25. package/angular/background-geolocation-events.ts +21 -0
  26. package/angular/background-geolocation.service.ts +63 -0
  27. package/angular/dist/background-geolocation-events.d.ts +18 -1
  28. package/angular/dist/background-geolocation.service.d.ts +36 -0
  29. package/angular/dist/esm2022/background-geolocation-events.mjs +22 -1
  30. package/angular/dist/esm2022/background-geolocation.service.mjs +35 -1
  31. package/angular/dist/fesm2022/josuelmm-cordova-background-geolocation.mjs +55 -0
  32. package/angular/dist/fesm2022/josuelmm-cordova-background-geolocation.mjs.map +1 -1
  33. package/ios/CDVBackgroundGeolocation/CDVBackgroundGeolocation.m +312 -1
  34. package/ios/common/BackgroundGeolocation/MAURBackgroundGeolocationFacade.h +22 -0
  35. package/ios/common/BackgroundGeolocation/MAURBackgroundGeolocationFacade.m +400 -15
  36. package/ios/common/BackgroundGeolocation/MAURBackgroundSync.h +12 -0
  37. package/ios/common/BackgroundGeolocation/MAURBackgroundSync.m +83 -5
  38. package/ios/common/BackgroundGeolocation/MAURConfig.h +15 -0
  39. package/ios/common/BackgroundGeolocation/MAURConfig.m +100 -3
  40. package/ios/common/BackgroundGeolocation/MAURDistanceFilterLocationProvider.m +29 -2
  41. package/ios/common/BackgroundGeolocation/MAURPostLocationTask.h +4 -0
  42. package/ios/common/BackgroundGeolocation/MAURPostLocationTask.m +97 -44
  43. package/ios/common/BackgroundGeolocation/MAURSensorFusionDetector.h +41 -0
  44. package/ios/common/BackgroundGeolocation/MAURSensorFusionDetector.m +137 -0
  45. package/ios/common/BackgroundGeolocation/MAURUrlTemplateResolver.h +31 -0
  46. package/ios/common/BackgroundGeolocation/MAURUrlTemplateResolver.m +107 -0
  47. package/package.json +41 -1
  48. package/plugin.xml +19 -8
  49. package/www/BackgroundGeolocation.d.ts +517 -3
  50. package/www/BackgroundGeolocation.js +54 -1
  51. package/RELEASE.MD +0 -16
package/README.md CHANGED
@@ -193,15 +193,19 @@ Set your preferred provider, accuracy, intervals, and optional server URLs. All
193
193
  | `syncUrl` | Server URL where **pending** locations are sent in batch (when count reaches `syncThreshold` or on `forceSync()`) |
194
194
  | `syncThreshold` | Number of pending locations before automatic batch sync (default 100) |
195
195
  | `sync` | When `true` (default), automatic sync and `forceSync()` run. When `false`, sync is disabled (locations are still stored). |
196
- | `httpHeaders` | Headers for every POST (e.g. `{ 'Content-Type': 'application/json', 'Authorization': 'Bearer TOKEN' }`) |
197
- | `postTemplate` | Object or array of properties to send (use `@latitude`, `@longitude`, etc.). See [Custom post template](docs/api.md#custom-post-template). |
196
+ | `httpHeaders` / `headers` | Headers for every request (e.g. `{ 'Content-Type': 'application/json', 'Authorization': 'Bearer TOKEN' }`). `headers` is the alias added in 3.3.0; both are supported. |
197
+ | `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
+ | `syncHttpMethod` | **Since 3.3.0.** HTTP method for `syncUrl`. Same values as `httpMethod`. |
199
+ | `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). |
201
+ | `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. |
198
202
  | `maxLocations` | Max locations kept in DB (default 10000). Should be > `syncThreshold`. |
199
203
 
200
204
  **Android-only:** `notificationSyncTitle`, `notificationSyncText`, `notificationSyncCompletedText`, `notificationSyncFailedText` — texts shown in the notification while syncing (defaults in English; set for localization). `startForeground`, `notificationsEnabled`, `startOnBoot`, `stopOnTerminate`, `enableWatchdog`.
201
205
 
202
- **iOS-only:** `activityType`, `pauseLocationUpdates`, `saveBatteryOnBackground`.
206
+ **iOS-only:** `activityType`, `pauseLocationUpdates`, `saveBatteryOnBackground`, `showsBackgroundLocationIndicator` (since 3.4.0; iOS 11+, shows the blue background indicator).
203
207
 
204
- Example:
208
+ Example (default POST + JSON):
205
209
 
206
210
  ```js
207
211
  BackgroundGeolocation.configure({
@@ -215,6 +219,8 @@ BackgroundGeolocation.configure({
215
219
  interval: 10000,
216
220
  fastestInterval: 5000,
217
221
  activitiesInterval: 10000,
222
+ startOnBoot: true,
223
+ stopOnTerminate: false,
218
224
  url: 'https://yourserver.com/location',
219
225
  syncUrl: 'https://yourserver.com/location',
220
226
  syncThreshold: 5,
@@ -231,6 +237,21 @@ BackgroundGeolocation.configure({
231
237
  });
232
238
  ```
233
239
 
240
+ Example (since 3.3.0, GET with URL templating — works against Traccar OsmAnd, GPSWox, custom REST, etc.):
241
+
242
+ ```js
243
+ BackgroundGeolocation.configure({
244
+ url: 'https://your-backend/track?uid={uid}&lat={latitude}&lon={longitude}&t={timestamp_iso}&spd={speed}',
245
+ httpMethod: 'GET',
246
+ httpMode: 'single',
247
+ queryParams: { uid: 'USER_DEVICE_123' },
248
+ startOnBoot: true,
249
+ stopOnTerminate: false
250
+ });
251
+ ```
252
+
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.
254
+
234
255
  ### 2. Start tracking
235
256
 
236
257
  ```js
@@ -347,6 +368,87 @@ Subscribe with `BackgroundGeolocation.on(eventName, callback)`. Unsubscribe with
347
368
 
348
369
  Full event payloads and options: [Events](docs/events.md). Full API (all options, all methods): [API](docs/api.md).
349
370
 
371
+ ### New in 4.2.2
372
+
373
+ - Build hotfixes — required when consuming the plugin via Capacitor (Gradle 8.x):
374
+ - `PostLocationTask.postLocation`: cast `LocationTemplate.locationToJson` (returns `Object`) to the right `HttpPostService.postJSON` overload.
375
+ - `BackgroundGeolocationPlugin.buildDiagnostics`: wrap `facade.locationServicesEnabled()` in `try/catch (PluginException)`.
376
+
377
+ ### New in 4.2.0
378
+
379
+ - **Real sensor fusion (Phase 8).** Optional accelerometer + gyroscope pipeline (`drivingEvents.sensorFusion: true`). On Android uses `Sensor.TYPE_LINEAR_ACCELERATION` + `Sensor.TYPE_GYROSCOPE`; on iOS uses `CMMotionManager.startDeviceMotionUpdatesToQueue` at 50 Hz.
380
+ - **Sensor-driven `possibleCrash`.** When the pipeline detects `|a| ≥ crashImpactG` (default 3 g) during an active trip, emits `possibleCrash` with `source: "sensor"`. GPS-derived `possibleCrash` keeps emitting with `source: "gps"`. Detects parking-lot impacts that GPS alone misses.
381
+ - **New event `phoneUsageWhileDriving`.** Sustained device interaction (gyro/accel jitter + screen on) during an active trip.
382
+ - New thresholds in `drivingEvents`: `crashImpactG`, `sensorCrashCooldownMs`, `phoneUsageWindowMs`, `phoneUsageCooldownMs`.
383
+ - Hot-reload: changes to `drivingEvents.sensorFusion` via `configure()` (re)start the pipeline without a full service restart.
384
+ - Battery: pipeline only samples while a trip is active. Off by default — opt in with `sensorFusion: true`.
385
+
386
+ ```javascript
387
+ BackgroundGeolocation.configure({
388
+ drivingEvents: {
389
+ enabled: true,
390
+ sensorFusion: true, // v4.2 — opt in
391
+ crashImpactG: 3.0, // |a| in g for sensor-driven possibleCrash (default 3.0)
392
+ phoneUsageWindowMs: 4000,
393
+ phoneUsageCooldownMs: 60000
394
+ }
395
+ });
396
+
397
+ BackgroundGeolocation.on('possibleCrash', (d) => {
398
+ // d.source === 'gps' (GPS heuristic) or 'sensor' (accelerometer impact, higher confidence)
399
+ });
400
+ BackgroundGeolocation.on('phoneUsageWhileDriving', (location) => {
401
+ // Sustained device interaction during an active trip with the screen on.
402
+ });
403
+ ```
404
+
405
+ Full reference (all thresholds, when to enable, iOS screen-on caveat): [docs/api.md → Driver insights](docs/api.md#driver-insights-since-400).
406
+
407
+ ### New in 4.1.0
408
+
409
+ - **GPS-derived driving events.** Four new events: `hardBrake`, `rapidAcceleration`, `sharpTurn`, `possibleCrash`. All derived from GPS speed and bearing — **no accelerometer/gyroscope required**. Configure thresholds via the extended `drivingEvents` config (`hardBrakeMps2`, `rapidAccelMps2`, `sharpTurnDegPerSec`, `crashImpactKmh`, `crashWindowMs`). Each event has a 4 s cooldown.
410
+ - `possibleCrash` is heuristic. **Always confirm with the user** before notifying contacts; false positives are expected (sudden tunnel exit, GPS glitches).
411
+ - TypeScript: 4 new typed `on()` overloads with `{ location, value }` payloads.
412
+ - v4.2 adds real sensor fusion on top of these events.
413
+
414
+ ### New in 4.0.0
415
+
416
+ - **Driver insights (Phase 6).** New GPS-only state machine emits `tripStart`, `tripEnd`, `moving`, `stopped`, `speeding`, `providerChange`, `sos` events end-to-end (Android + iOS). Configure thresholds via the new `drivingEvents` option.
417
+ - New method **`triggerSOS(payload?)`** — fires a single `sos` event with the latest known location plus your payload. The host app handles the actual SOS workflow (notify contacts, push, alarm UI).
418
+ - The Angular service exposes `triggerSOS()`.
419
+ - ✅ Driving events (`hardBrake`, `rapidAcceleration`, `sharpTurn`, `possibleCrash`) ya están disponibles en v4.1.0 — derivados de GPS (sin sensores adicionales). Real sensor fusion (acelerómetro/giroscopio) se planea para v4.2.
420
+
421
+ ### New in 3.6.0
422
+
423
+ - **Battery / OEM helpers (Phase 5).** Five new methods to guide the user through the steps required for reliable background tracking on aggressive OEMs:
424
+ - `isIgnoringBatteryOptimizations()` — Android Doze whitelist state.
425
+ - `requestIgnoreBatteryOptimizations()` — opens the system dialog.
426
+ - `openBatterySettings()` — opens the per-app battery screen.
427
+ - `openAutoStartSettings()` — opens the OEM-specific auto-start screen on Xiaomi MIUI, Huawei EMUI, Oppo ColorOS, Vivo FunTouch, OnePlus, Asus (Samsung falls back to app-info).
428
+ - `getManufacturerHelp()` — returns OEM-specific guidance text the app can render as a help screen.
429
+ - The Angular service exposes all 5 methods.
430
+ - Combine with `getDiagnostics()` to build a "Tracking is being killed by your phone — fix it here" flow.
431
+
432
+ ### New in 3.5.0
433
+
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).
435
+ - **`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
+ - **`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
+ - The Angular service exposes `getDiagnostics()` directly.
438
+
439
+ ### New in 3.4.0
440
+
441
+ - **Location API modernization (Phase 3).** The Android Activity provider now uses `LocationRequest.Builder` + `Priority.PRIORITY_*` (replaces the deprecated `LocationRequest.create()` / `setPriority` / `setInterval` / `LocationRequest.PRIORITY_*` family from `play-services-location 21.0.0+`). The Distance Filter and Raw providers no longer use the deprecated `Criteria` API; provider selection is now an explicit GPS-first / Network-fallback. iOS migrates `[NSURLConnection sendSynchronousRequest:]` (deprecated since iOS 9) to `NSURLSession + dispatch_semaphore`, and adds the iOS 14+ `locationManagerDidChangeAuthorization:` callback alongside the legacy one.
442
+ - **`showsBackgroundLocationIndicator`** (iOS 11+). Set to `true` to display the blue status indicator while the app uses location in the background.
443
+ - **Bug fixes:** iOS `activitiesInterval` is now correctly read from the dictionary (the previous `isNull` check was inverted, dropping user input). Android `Content-Length` is computed in UTF-8 byte length instead of `String.length()`, so multi-byte characters (`ñ`, `é`, emoji) no longer mismatch the body size.
444
+ - **Default `GOOGLE_PLAY_SERVICES_VERSION`** raised to `21.0.1`. Apps that override it via `--variable` keep their override.
445
+
446
+ ### New in 3.3.0
447
+
448
+ - **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).
450
+ - **Engines:** `cordova-android >= 12.0.0` is now the minimum.
451
+
350
452
  ### New in 3.2.0
351
453
 
352
454
  - **Session API for route/recording** — Store all locations for the *current route* in the plugin, independent of sync. When the user reopens the app without internet, you can restore the full track from the plugin (no need for `localStorage` for points).
@@ -435,6 +537,89 @@ No extra wrapper (e.g. Awesome Cordova Plugins) is required.
435
537
 
436
538
  ## Compatibility
437
539
 
540
+ | Plugin version | Cordova CLI | Cordova Android | Cordova iOS |
541
+ |----------------|-------------|-----------------|-------------|
542
+ | 1.x | ≥ 8.0.0 | ≥ 8.0.0 | ≥ 6.0.0 |
543
+ | 2.x | ≥ 10.0.0 | ≥ 10.0.0 | ≥ 6.0.0 |
544
+ | 3.0.x – 3.2.x | ≥ 10.0.0 | ≥ 10.0.0 | ≥ 6.0.0 |
545
+ | 3.3.x – 4.1.x | ≥ 10.0.0 | ≥ 12.0.0 | ≥ 6.2.0 |
546
+
547
+ > 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.
548
+
549
+ ---
550
+
551
+ ## Documentation and changelog
552
+
553
+ 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/)).
554
+
555
+ | Doc | What you'll find |
556
+ |-----|------------------|
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
+
438
623
  | Plugin version | Cordova CLI | Cordova Android | Cordova iOS |
439
624
  |----------------|-------------|-----------------|-------------|
440
625
  | 1.x | ≥ 8.0.0 | ≥ 8.0.0 | ≥ 6.0.0 |
@@ -99,12 +99,17 @@ public class ConfigMapper {
99
99
  if (jObject.has("sync")) {
100
100
  config.setSyncEnabled(jObject.getBoolean("sync"));
101
101
  }
102
+ // headers (alias of httpHeaders)
102
103
  if (jObject.has("httpHeaders")) {
103
104
  config.setHttpHeaders(jObject.getJSONObject("httpHeaders"));
104
105
  }
106
+ if (jObject.has("headers")) {
107
+ config.setHttpHeaders(jObject.getJSONObject("headers"));
108
+ }
105
109
  if (jObject.has("maxLocations")) {
106
110
  config.setMaxLocations(jObject.getInt("maxLocations"));
107
111
  }
112
+ // bodyTemplate (alias of postTemplate)
108
113
  if (jObject.has("postTemplate")) {
109
114
  if (jObject.isNull("postTemplate")) {
110
115
  config.setTemplate(LocationTemplateFactory.getDefault());
@@ -113,6 +118,60 @@ public class ConfigMapper {
113
118
  config.setTemplate(LocationTemplateFactory.fromJSON(postTemplate));
114
119
  }
115
120
  }
121
+ if (jObject.has("bodyTemplate")) {
122
+ if (jObject.isNull("bodyTemplate")) {
123
+ config.setTemplate(LocationTemplateFactory.getDefault());
124
+ } else {
125
+ Object bodyTemplate = jObject.get("bodyTemplate");
126
+ config.setTemplate(LocationTemplateFactory.fromJSON(bodyTemplate));
127
+ }
128
+ }
129
+ // v3.3 Phase 2: HTTP transport
130
+ if (jObject.has("httpMethod") && !jObject.isNull("httpMethod")) {
131
+ config.setHttpMethod(jObject.getString("httpMethod"));
132
+ }
133
+ if (jObject.has("syncHttpMethod") && !jObject.isNull("syncHttpMethod")) {
134
+ config.setSyncHttpMethod(jObject.getString("syncHttpMethod"));
135
+ }
136
+ if (jObject.has("httpMode") && !jObject.isNull("httpMode")) {
137
+ config.setHttpMode(jObject.getString("httpMode"));
138
+ }
139
+ if (jObject.has("syncMode") && !jObject.isNull("syncMode")) {
140
+ config.setSyncMode(jObject.getString("syncMode"));
141
+ }
142
+ if (jObject.has("queryParams") && !jObject.isNull("queryParams")) {
143
+ config.setQueryParams(jObject.getJSONObject("queryParams"));
144
+ }
145
+ if (jObject.has("heartbeatInterval") && !jObject.isNull("heartbeatInterval")) {
146
+ config.setHeartbeatInterval(jObject.getInt("heartbeatInterval"));
147
+ }
148
+ if (jObject.has("mockLocationPolicy") && !jObject.isNull("mockLocationPolicy")) {
149
+ config.setMockLocationPolicy(jObject.getString("mockLocationPolicy"));
150
+ }
151
+ // v4.0 Phase 6: drivingEvents
152
+ if (jObject.has("drivingEvents") && !jObject.isNull("drivingEvents")) {
153
+ JSONObject de = jObject.getJSONObject("drivingEvents");
154
+ Config.DrivingEventsOptions opts = new Config.DrivingEventsOptions();
155
+ if (de.has("enabled")) opts.enabled = de.getBoolean("enabled");
156
+ if (de.has("speedLimit")) opts.speedLimitKmh = de.getDouble("speedLimit");
157
+ if (de.has("minMovingSpeed")) opts.minMovingSpeedMps = de.getDouble("minMovingSpeed");
158
+ if (de.has("stoppedDuration")) opts.stoppedDurationMs = de.getLong("stoppedDuration");
159
+ if (de.has("minTripSpeed")) opts.minTripSpeedMps = de.getDouble("minTripSpeed");
160
+ if (de.has("minTripDuration")) opts.minTripDurationMs = de.getLong("minTripDuration");
161
+ // v4.1
162
+ if (de.has("hardBrakeMps2")) opts.hardBrakeMps2 = de.getDouble("hardBrakeMps2");
163
+ if (de.has("rapidAccelMps2")) opts.rapidAccelMps2 = de.getDouble("rapidAccelMps2");
164
+ if (de.has("sharpTurnDegPerSec")) opts.sharpTurnDegPerSec = de.getDouble("sharpTurnDegPerSec");
165
+ if (de.has("crashImpactKmh")) opts.crashImpactKmh = de.getDouble("crashImpactKmh");
166
+ if (de.has("crashWindowMs")) opts.crashWindowMs = de.getLong("crashWindowMs");
167
+ // v4.2 sensor fusion
168
+ if (de.has("sensorFusion")) opts.sensorFusion = de.getBoolean("sensorFusion");
169
+ if (de.has("crashImpactG")) opts.crashImpactG = de.getDouble("crashImpactG");
170
+ if (de.has("sensorCrashCooldownMs"))opts.sensorCrashCooldownMs = de.getLong("sensorCrashCooldownMs");
171
+ if (de.has("phoneUsageWindowMs")) opts.phoneUsageWindowMs = de.getLong("phoneUsageWindowMs");
172
+ if (de.has("phoneUsageCooldownMs")) opts.phoneUsageCooldownMs = de.getLong("phoneUsageCooldownMs");
173
+ config.setDrivingEvents(opts);
174
+ }
116
175
  if (jObject.has("enableWatchdog")) {
117
176
  config.setEnableWatchdog(jObject.getBoolean("enableWatchdog"));
118
177
  }
@@ -175,6 +234,37 @@ public class ConfigMapper {
175
234
 
176
235
  json.put("postTemplate", template);
177
236
 
237
+ json.put("httpMethod", config.getHttpMethod());
238
+ json.put("syncHttpMethod", config.getSyncHttpMethod());
239
+ json.put("httpMode", config.getHttpMode());
240
+ json.put("syncMode", config.getSyncMode());
241
+ json.put("queryParams", config.getQueryParams() != null ? new JSONObject(config.getQueryParams()) : JSONObject.NULL);
242
+ json.put("heartbeatInterval", config.getHeartbeatInterval());
243
+ json.put("mockLocationPolicy", config.getMockLocationPolicy());
244
+
245
+ Config.DrivingEventsOptions de = config.getDrivingEvents();
246
+ if (de != null) {
247
+ JSONObject deJson = new JSONObject();
248
+ deJson.put("enabled", de.enabled);
249
+ deJson.put("speedLimit", de.speedLimitKmh);
250
+ deJson.put("minMovingSpeed", de.minMovingSpeedMps);
251
+ deJson.put("stoppedDuration", de.stoppedDurationMs);
252
+ deJson.put("minTripSpeed", de.minTripSpeedMps);
253
+ deJson.put("minTripDuration", de.minTripDurationMs);
254
+ deJson.put("hardBrakeMps2", de.hardBrakeMps2);
255
+ deJson.put("rapidAccelMps2", de.rapidAccelMps2);
256
+ deJson.put("sharpTurnDegPerSec", de.sharpTurnDegPerSec);
257
+ deJson.put("crashImpactKmh", de.crashImpactKmh);
258
+ deJson.put("crashWindowMs", de.crashWindowMs);
259
+ // v4.2 sensor fusion
260
+ deJson.put("sensorFusion", de.sensorFusion);
261
+ deJson.put("crashImpactG", de.crashImpactG);
262
+ deJson.put("sensorCrashCooldownMs", de.sensorCrashCooldownMs);
263
+ deJson.put("phoneUsageWindowMs", de.phoneUsageWindowMs);
264
+ deJson.put("phoneUsageCooldownMs", de.phoneUsageCooldownMs);
265
+ json.put("drivingEvents", deJson);
266
+ }
267
+
178
268
  return json;
179
269
  }
180
270
  }