react-native-nitro-location-tracking 0.1.7 → 0.1.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (22) hide show
  1. package/README.md +179 -87
  2. package/android/src/main/java/com/margelo/nitro/nitrolocationtracking/GeofenceManager.kt +10 -0
  3. package/android/src/main/java/com/margelo/nitro/nitrolocationtracking/LocationEngine.kt +3 -0
  4. package/android/src/main/java/com/margelo/nitro/nitrolocationtracking/NitroLocationTracking.kt +83 -7
  5. package/ios/GeofenceManager.swift +6 -0
  6. package/ios/LocationEngine.swift +51 -8
  7. package/ios/NitroLocationTracking.swift +38 -2
  8. package/lib/typescript/src/NitroLocationTracking.nitro.d.ts +3 -0
  9. package/lib/typescript/src/NitroLocationTracking.nitro.d.ts.map +1 -1
  10. package/nitrogen/generated/android/c++/JHybridNitroLocationTrackingSpec.cpp +26 -0
  11. package/nitrogen/generated/android/c++/JHybridNitroLocationTrackingSpec.hpp +3 -0
  12. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrolocationtracking/HybridNitroLocationTrackingSpec.kt +12 -0
  13. package/nitrogen/generated/ios/NitroLocationTracking-Swift-Cxx-Bridge.cpp +8 -0
  14. package/nitrogen/generated/ios/NitroLocationTracking-Swift-Cxx-Bridge.hpp +43 -0
  15. package/nitrogen/generated/ios/c++/HybridNitroLocationTrackingSpecSwift.hpp +24 -0
  16. package/nitrogen/generated/ios/swift/Func_void_PermissionStatus.swift +46 -0
  17. package/nitrogen/generated/ios/swift/HybridNitroLocationTrackingSpec.swift +3 -0
  18. package/nitrogen/generated/ios/swift/HybridNitroLocationTrackingSpec_cxx.swift +43 -0
  19. package/nitrogen/generated/shared/c++/HybridNitroLocationTrackingSpec.cpp +3 -0
  20. package/nitrogen/generated/shared/c++/HybridNitroLocationTrackingSpec.hpp +3 -0
  21. package/package.json +1 -1
  22. package/src/NitroLocationTracking.nitro.ts +10 -0
package/README.md CHANGED
@@ -91,7 +91,8 @@ const granted = await requestLocationPermission(
91
91
  },
92
92
  {
93
93
  title: 'Background Location',
94
- message: 'Allow background location to keep tracking while the app is minimized.',
94
+ message:
95
+ 'Allow background location to keep tracking while the app is minimized.',
95
96
  buttonPositive: 'Allow',
96
97
  buttonNegative: 'Deny',
97
98
  }
@@ -109,13 +110,13 @@ import { useDriverLocation } from 'react-native-nitro-location-tracking';
109
110
  import type { LocationConfig } from 'react-native-nitro-location-tracking';
110
111
 
111
112
  const config: LocationConfig = {
112
- desiredAccuracy: 'high', // 'high' | 'balanced' | 'low'
113
- distanceFilter: 10, // meters
114
- intervalMs: 3000, // Android only
115
- fastestIntervalMs: 1000, // Android only
116
- stopTimeout: 5, // minutes before declaring stopped
117
- stopOnTerminate: false, // keep tracking after app close (Android)
118
- startOnBoot: true, // restart tracking after reboot (Android)
113
+ desiredAccuracy: 'high', // 'high' | 'balanced' | 'low'
114
+ distanceFilter: 10, // meters
115
+ intervalMs: 3000, // Android only
116
+ fastestIntervalMs: 1000, // Android only
117
+ stopTimeout: 5, // minutes before declaring stopped
118
+ stopOnTerminate: false, // keep tracking after app close (Android)
119
+ startOnBoot: true, // restart tracking after reboot (Android)
119
120
  foregroundNotificationTitle: 'Tracking Active',
120
121
  foregroundNotificationText: 'Your location is being tracked',
121
122
  };
@@ -155,8 +156,8 @@ const connectionConfig: ConnectionConfig = {
155
156
  authToken: 'your-auth-token',
156
157
  reconnectIntervalMs: 5000,
157
158
  maxReconnectAttempts: 10,
158
- batchSize: 5, // locations per batch upload
159
- syncIntervalMs: 10000, // flush queue every 10s
159
+ batchSize: 5, // locations per batch upload
160
+ syncIntervalMs: 10000, // flush queue every 10s
160
161
  };
161
162
 
162
163
  function RideScreen() {
@@ -238,10 +239,10 @@ NitroLocationModule.onLocation((location) => {
238
239
 
239
240
  **Platform behavior:**
240
241
 
241
- | Platform | Per-location detection | Device-level detection |
242
- |----------|----------------------|------------------------|
243
- | Android | `Location.isMock` (API 31+) / `isFromMockProvider` (API 18+) | `AppOpsManager` mock location check |
244
- | iOS | `CLLocation.sourceInformation.isSimulatedBySoftware` (iOS 15+) | Simulator detection |
242
+ | Platform | Per-location detection | Device-level detection |
243
+ | -------- | -------------------------------------------------------------- | ----------------------------------- |
244
+ | Android | `Location.isMock` (API 31+) / `isFromMockProvider` (API 18+) | `AppOpsManager` mock location check |
245
+ | iOS | `CLLocation.sourceInformation.isSimulatedBySoftware` (iOS 15+) | Simulator detection |
245
246
 
246
247
  ### Smooth Map Marker Animation
247
248
 
@@ -287,7 +288,10 @@ function MapScreen() {
287
288
  Calculate bearing between two coordinates and handle rotation smoothing:
288
289
 
289
290
  ```tsx
290
- import { calculateBearing, shortestRotation } from 'react-native-nitro-location-tracking';
291
+ import {
292
+ calculateBearing,
293
+ shortestRotation,
294
+ } from 'react-native-nitro-location-tracking';
291
295
 
292
296
  // Calculate bearing from point A to point B (in degrees, 0-360)
293
297
  const bearing = calculateBearing(
@@ -333,6 +337,49 @@ NitroLocationModule.removeAllGeofences();
333
337
 
334
338
  > **Note:** iOS limits geofence regions to 20 per app. Android supports up to 100.
335
339
 
340
+ ### Distance Utilities
341
+
342
+ Calculate distance between two points or from the current location to a registered geofence:
343
+
344
+ ```tsx
345
+ import NitroLocationModule from 'react-native-nitro-location-tracking';
346
+
347
+ // Calculate distance between any two coordinates (returns meters)
348
+ const meters = NitroLocationModule.getDistanceBetween(
349
+ 41.311158,
350
+ 69.279737, // point A
351
+ 41.3152,
352
+ 69.2851 // point B
353
+ );
354
+ console.log(`Distance: ${meters.toFixed(0)}m`);
355
+
356
+ // Get distance from current location to a registered geofence center
357
+ // First, register a geofence
358
+ NitroLocationModule.addGeofence({
359
+ id: 'branch-123',
360
+ latitude: 41.311158,
361
+ longitude: 69.279737,
362
+ radius: 150,
363
+ notifyOnEntry: true,
364
+ notifyOnExit: true,
365
+ });
366
+
367
+ // Then query distance using the same region id
368
+ const distToBranch = NitroLocationModule.getDistanceToGeofence('branch-123');
369
+ if (distToBranch >= 0) {
370
+ console.log(`Distance to branch: ${distToBranch.toFixed(0)}m`);
371
+ } else {
372
+ console.warn('Geofence not found or no location available');
373
+ }
374
+ ```
375
+
376
+ **Key points:**
377
+
378
+ - Both methods use **native distance APIs** (`CLLocation.distance(from:)` on iOS, `Location.distanceBetween()` on Android) — no JS-thread computation.
379
+ - `getDistanceBetween()` is a pure utility — pass any two lat/lng pairs.
380
+ - `getDistanceToGeofence()` uses the device's **last known native location** and the registered geofence center. Returns `-1` if the region ID is not found or no location is available.
381
+ - The `regionId` is the `id` string you set when calling `addGeofence()`.
382
+
336
383
  ### Speed Monitoring
337
384
 
338
385
  Get alerts when speed crosses configurable thresholds:
@@ -342,9 +389,9 @@ import NitroLocationModule from 'react-native-nitro-location-tracking';
342
389
 
343
390
  // Configure speed thresholds
344
391
  NitroLocationModule.configureSpeedMonitor({
345
- maxSpeedKmh: 120, // alert when exceeding 120 km/h
346
- minSpeedKmh: 5, // alert when below 5 km/h (idle detection)
347
- checkIntervalMs: 0, // check on every location update
392
+ maxSpeedKmh: 120, // alert when exceeding 120 km/h
393
+ minSpeedKmh: 5, // alert when below 5 km/h (idle detection)
394
+ checkIntervalMs: 0, // check on every location update
348
395
  });
349
396
 
350
397
  // Listen for speed state transitions
@@ -434,13 +481,55 @@ switch (status) {
434
481
  }
435
482
  ```
436
483
 
437
- | Status | iOS | Android |
438
- |--------|-----|----------|
439
- | `notDetermined` | Not yet asked | N/A (returns `denied`) |
440
- | `denied` | User denied | Fine location not granted |
441
- | `restricted` | Parental/MDM restriction | N/A (returns `denied`) |
442
- | `whenInUse` | Authorized when in use | Fine granted, background not |
443
- | `always` | Authorized always | Fine + background granted |
484
+ | Status | iOS | Android |
485
+ | --------------- | ------------------------ | ---------------------------- |
486
+ | `notDetermined` | Not yet asked | N/A (returns `denied`) |
487
+ | `denied` | User denied | Fine location not granted |
488
+ | `restricted` | Parental/MDM restriction | N/A (returns `denied`) |
489
+ | `whenInUse` | Authorized when in use | Fine granted, background not |
490
+ | `always` | Authorized always | Fine + background granted |
491
+
492
+ ### Request Permission (Native)
493
+
494
+ Request location permission directly via the native module and get the resulting status:
495
+
496
+ ```tsx
497
+ import NitroLocationModule from 'react-native-nitro-location-tracking';
498
+
499
+ async function setup() {
500
+ // Check current status first (no dialog)
501
+ const current = NitroLocationModule.getLocationPermissionStatus();
502
+
503
+ if (current === 'always' || current === 'whenInUse') {
504
+ // Already granted — start tracking
505
+ NitroLocationModule.startTracking();
506
+ return;
507
+ }
508
+
509
+ // Request permission — shows the system dialog
510
+ const status = await NitroLocationModule.requestLocationPermission();
511
+
512
+ switch (status) {
513
+ case 'always':
514
+ case 'whenInUse':
515
+ NitroLocationModule.startTracking();
516
+ break;
517
+ case 'denied':
518
+ Alert.alert('Location Required', 'Please enable location in Settings');
519
+ break;
520
+ case 'restricted':
521
+ // Parental controls / MDM — cannot request
522
+ break;
523
+ }
524
+ }
525
+ ```
526
+
527
+ **Platform behavior:**
528
+
529
+ | Platform | Behavior |
530
+ | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
531
+ | iOS | Calls `requestAlwaysAuthorization()`. If permission is already determined, resolves immediately with current status. If `start()` was called before permission was granted, tracking auto-starts once the user allows. |
532
+ | Android | Uses React Native's `PermissionAwareActivity` to show the system permission dialog for `ACCESS_FINE_LOCATION` + `ACCESS_COARSE_LOCATION`. Resolves with the resulting status after the user responds. |
444
533
 
445
534
  ## API Reference
446
535
 
@@ -453,11 +542,11 @@ interface LocationData {
453
542
  latitude: number;
454
543
  longitude: number;
455
544
  altitude: number;
456
- speed: number; // m/s
457
- bearing: number; // degrees
458
- accuracy: number; // meters
459
- timestamp: number; // unix ms
460
- isMockLocation?: boolean; // true when from a mock provider
545
+ speed: number; // m/s
546
+ bearing: number; // degrees
547
+ accuracy: number; // meters
548
+ timestamp: number; // unix ms
549
+ isMockLocation?: boolean; // true when from a mock provider
461
550
  }
462
551
  ```
463
552
 
@@ -466,12 +555,12 @@ interface LocationData {
466
555
  ```ts
467
556
  interface LocationConfig {
468
557
  desiredAccuracy: 'high' | 'balanced' | 'low';
469
- distanceFilter: number; // meters
470
- intervalMs: number; // Android only
471
- fastestIntervalMs: number; // Android only
472
- stopTimeout: number; // minutes before declaring stopped
473
- stopOnTerminate: boolean; // keep tracking after app close (Android)
474
- startOnBoot: boolean; // restart tracking after reboot (Android)
558
+ distanceFilter: number; // meters
559
+ intervalMs: number; // Android only
560
+ fastestIntervalMs: number; // Android only
561
+ stopTimeout: number; // minutes before declaring stopped
562
+ stopOnTerminate: boolean; // keep tracking after app close (Android)
563
+ startOnBoot: boolean; // restart tracking after reboot (Android)
475
564
  foregroundNotificationTitle: string;
476
565
  foregroundNotificationText: string;
477
566
  }
@@ -486,7 +575,7 @@ interface ConnectionConfig {
486
575
  authToken: string;
487
576
  reconnectIntervalMs: number;
488
577
  maxReconnectAttempts: number;
489
- batchSize: number; // locations per batch upload
578
+ batchSize: number; // locations per batch upload
490
579
  syncIntervalMs: number; // how often to flush queue
491
580
  }
492
581
  ```
@@ -498,7 +587,7 @@ interface GeofenceRegion {
498
587
  id: string;
499
588
  latitude: number;
500
589
  longitude: number;
501
- radius: number; // meters
590
+ radius: number; // meters
502
591
  notifyOnEntry: boolean;
503
592
  notifyOnExit: boolean;
504
593
  }
@@ -508,9 +597,9 @@ interface GeofenceRegion {
508
597
 
509
598
  ```ts
510
599
  interface SpeedConfig {
511
- maxSpeedKmh: number; // speed limit in km/h
512
- minSpeedKmh: number; // minimum speed threshold
513
- checkIntervalMs: number; // how often to evaluate
600
+ maxSpeedKmh: number; // speed limit in km/h
601
+ minSpeedKmh: number; // minimum speed threshold
602
+ checkIntervalMs: number; // how often to evaluate
514
603
  }
515
604
  ```
516
605
 
@@ -539,58 +628,61 @@ type PermissionStatus =
539
628
 
540
629
  ### Hooks
541
630
 
542
- | Hook | Returns | Description |
543
- |------|---------|-------------|
544
- | `useDriverLocation(config)` | `{ location, isMoving, isTracking, startTracking, stopTracking }` | Manages location tracking lifecycle |
545
- | `useRideConnection(config)` | `{ connectionState, lastMessage, connect, disconnect, send }` | Manages WebSocket connection lifecycle |
631
+ | Hook | Returns | Description |
632
+ | --------------------------- | ----------------------------------------------------------------- | -------------------------------------- |
633
+ | `useDriverLocation(config)` | `{ location, isMoving, isTracking, startTracking, stopTracking }` | Manages location tracking lifecycle |
634
+ | `useRideConnection(config)` | `{ connectionState, lastMessage, connect, disconnect, send }` | Manages WebSocket connection lifecycle |
546
635
 
547
636
  ### Native Module Methods
548
637
 
549
- | Method | Returns | Description |
550
- |--------|---------|-------------|
551
- | `configure(config)` | `void` | Set location tracking configuration |
552
- | `startTracking()` | `void` | Start location tracking |
553
- | `stopTracking()` | `void` | Stop location tracking |
554
- | `getCurrentLocation()` | `Promise<LocationData>` | Get a one-shot location |
555
- | `isTracking()` | `boolean` | Check if tracking is active |
556
- | `onLocation(callback)` | `void` | Register location update callback |
557
- | `onMotionChange(callback)` | `void` | Register motion state callback |
558
- | `configureConnection(config)` | `void` | Set WebSocket/REST configuration |
559
- | `connectWebSocket()` | `void` | Open WebSocket connection |
560
- | `disconnectWebSocket()` | `void` | Close WebSocket connection |
561
- | `sendMessage(message)` | `void` | Send a message via WebSocket |
562
- | `getConnectionState()` | `ConnectionState` | Get current connection state |
563
- | `onConnectionStateChange(callback)` | `void` | Register connection state callback |
564
- | `onMessage(callback)` | `void` | Register incoming message callback |
565
- | `forceSync()` | `Promise<boolean>` | Flush queued locations to server |
566
- | `isFakeGpsEnabled()` | `boolean` | Check if device-level mock location is enabled |
567
- | `setRejectMockLocations(reject)` | `void` | Auto-reject mock locations when `true` |
568
- | `addGeofence(region)` | `void` | Start monitoring a circular geofence region |
569
- | `removeGeofence(regionId)` | `void` | Stop monitoring a specific geofence |
570
- | `removeAllGeofences()` | `void` | Remove all active geofences |
571
- | `onGeofenceEvent(callback)` | `void` | Register geofence enter/exit callback |
572
- | `configureSpeedMonitor(config)` | `void` | Set speed monitoring thresholds |
573
- | `onSpeedAlert(callback)` | `void` | Register speed state-transition callback |
574
- | `getCurrentSpeed()` | `number` | Get current speed in km/h |
575
- | `startTripCalculation()` | `void` | Start recording trip distance/stats |
576
- | `stopTripCalculation()` | `TripStats` | Stop recording and get final stats |
577
- | `getTripStats()` | `TripStats` | Get current trip stats without stopping |
578
- | `resetTripCalculation()` | `void` | Reset trip calculator |
579
- | `isLocationServicesEnabled()` | `boolean` | Check if GPS/location is enabled on device |
580
- | `onProviderStatusChange(callback)` | `void` | Register GPS/network provider status callback |
581
- | `getLocationPermissionStatus()` | `PermissionStatus` | Check current location permission without prompting |
582
- | `showLocalNotification(title, body)` | `void` | Show a local notification |
583
- | `updateForegroundNotification(title, body)` | `void` | Update the foreground service notification |
584
- | `destroy()` | `void` | Stop tracking and disconnect |
638
+ | Method | Returns | Description |
639
+ | -------------------------------------------- | --------------------------- | ---------------------------------------------------------------------------------------- |
640
+ | `configure(config)` | `void` | Set location tracking configuration |
641
+ | `startTracking()` | `void` | Start location tracking |
642
+ | `stopTracking()` | `void` | Stop location tracking |
643
+ | `getCurrentLocation()` | `Promise<LocationData>` | Get a one-shot location |
644
+ | `isTracking()` | `boolean` | Check if tracking is active |
645
+ | `onLocation(callback)` | `void` | Register location update callback |
646
+ | `onMotionChange(callback)` | `void` | Register motion state callback |
647
+ | `configureConnection(config)` | `void` | Set WebSocket/REST configuration |
648
+ | `connectWebSocket()` | `void` | Open WebSocket connection |
649
+ | `disconnectWebSocket()` | `void` | Close WebSocket connection |
650
+ | `sendMessage(message)` | `void` | Send a message via WebSocket |
651
+ | `getConnectionState()` | `ConnectionState` | Get current connection state |
652
+ | `onConnectionStateChange(callback)` | `void` | Register connection state callback |
653
+ | `onMessage(callback)` | `void` | Register incoming message callback |
654
+ | `forceSync()` | `Promise<boolean>` | Flush queued locations to server |
655
+ | `isFakeGpsEnabled()` | `boolean` | Check if device-level mock location is enabled |
656
+ | `setRejectMockLocations(reject)` | `void` | Auto-reject mock locations when `true` |
657
+ | `addGeofence(region)` | `void` | Start monitoring a circular geofence region |
658
+ | `removeGeofence(regionId)` | `void` | Stop monitoring a specific geofence |
659
+ | `removeAllGeofences()` | `void` | Remove all active geofences |
660
+ | `onGeofenceEvent(callback)` | `void` | Register geofence enter/exit callback |
661
+ | `getDistanceBetween(lat1, lon1, lat2, lon2)` | `number` | Calculate distance between two points in meters (native Haversine) |
662
+ | `getDistanceToGeofence(regionId)` | `number` | Get distance in meters from last known location to a geofence center (`-1` if not found) |
663
+ | `configureSpeedMonitor(config)` | `void` | Set speed monitoring thresholds |
664
+ | `onSpeedAlert(callback)` | `void` | Register speed state-transition callback |
665
+ | `getCurrentSpeed()` | `number` | Get current speed in km/h |
666
+ | `startTripCalculation()` | `void` | Start recording trip distance/stats |
667
+ | `stopTripCalculation()` | `TripStats` | Stop recording and get final stats |
668
+ | `getTripStats()` | `TripStats` | Get current trip stats without stopping |
669
+ | `resetTripCalculation()` | `void` | Reset trip calculator |
670
+ | `isLocationServicesEnabled()` | `boolean` | Check if GPS/location is enabled on device |
671
+ | `onProviderStatusChange(callback)` | `void` | Register GPS/network provider status callback |
672
+ | `getLocationPermissionStatus()` | `PermissionStatus` | Check current location permission without prompting |
673
+ | `requestLocationPermission()` | `Promise<PermissionStatus>` | Request location permission and return the resulting status |
674
+ | `showLocalNotification(title, body)` | `void` | Show a local notification |
675
+ | `updateForegroundNotification(title, body)` | `void` | Update the foreground service notification |
676
+ | `destroy()` | `void` | Stop tracking and disconnect |
585
677
 
586
678
  ### Utility Exports
587
679
 
588
- | Export | Description |
589
- |--------|-------------|
590
- | `LocationSmoother` | Class for smooth map marker animation between updates |
591
- | `calculateBearing(from, to)` | Calculate bearing between two coordinates (degrees, 0-360) |
592
- | `shortestRotation(from, to)` | Calculate shortest rotation path to avoid spinning |
593
- | `requestLocationPermission()` | Request location + notification permissions (Android) |
680
+ | Export | Description |
681
+ | ----------------------------- | ---------------------------------------------------------- |
682
+ | `LocationSmoother` | Class for smooth map marker animation between updates |
683
+ | `calculateBearing(from, to)` | Calculate bearing between two coordinates (degrees, 0-360) |
684
+ | `shortestRotation(from, to)` | Calculate shortest rotation path to avoid spinning |
685
+ | `requestLocationPermission()` | Request location + notification permissions (Android) |
594
686
 
595
687
  ## Publishing to npm
596
688
 
@@ -135,6 +135,16 @@ class GeofenceManager(private val context: Context) {
135
135
  }
136
136
  }
137
137
 
138
+ fun distanceTo(regionId: String, lastLocation: android.location.Location?): Double {
139
+ val region = activeRegions[regionId] ?: return -1.0
140
+ val loc = lastLocation ?: return -1.0
141
+ val results = FloatArray(1)
142
+ android.location.Location.distanceBetween(
143
+ loc.latitude, loc.longitude, region.latitude, region.longitude, results
144
+ )
145
+ return results[0].toDouble()
146
+ }
147
+
138
148
  fun destroy() {
139
149
  removeAllGeofences()
140
150
  receiver?.let {
@@ -28,6 +28,8 @@ class LocationEngine(private val context: Context) {
28
28
  val tripCalculator = TripCalculator()
29
29
  private var lastSpeed = 0f
30
30
  private var tracking = false
31
+ var lastLocation: Location? = null
32
+ private set
31
33
 
32
34
  val isTracking: Boolean get() = tracking
33
35
 
@@ -90,6 +92,7 @@ class LocationEngine(private val context: Context) {
90
92
  // }
91
93
 
92
94
  private fun processLocation(location: Location) {
95
+ lastLocation = location
93
96
  val data = locationToData(location)
94
97
 
95
98
  // Skip mock locations if rejection is enabled
@@ -1,7 +1,11 @@
1
1
  package com.margelo.nitro.nitrolocationtracking
2
2
 
3
+ import android.content.pm.PackageManager
3
4
  import android.util.Log
5
+ import androidx.core.app.ActivityCompat
6
+ import androidx.core.content.ContextCompat
4
7
  import com.facebook.proguard.annotations.DoNotStrip
8
+ import com.facebook.react.bridge.ReactContext
5
9
  import com.margelo.nitro.NitroModules
6
10
  import com.margelo.nitro.core.Promise
7
11
  import kotlin.coroutines.resume
@@ -13,6 +17,7 @@ class NitroLocationTracking : HybridNitroLocationTrackingSpec() {
13
17
 
14
18
  companion object {
15
19
  private const val TAG = "NitroLocationTracking"
20
+ private const val PERMISSION_REQUEST_CODE = 9001
16
21
  }
17
22
 
18
23
  private var locationEngine: LocationEngine? = null
@@ -32,6 +37,7 @@ class NitroLocationTracking : HybridNitroLocationTrackingSpec() {
32
37
 
33
38
  private var locationConfig: LocationConfig? = null
34
39
 
40
+
35
41
  private fun ensureInitialized(): Boolean {
36
42
  if (locationEngine != null) return true
37
43
  val context = NitroModules.applicationContext
@@ -260,22 +266,19 @@ class NitroLocationTracking : HybridNitroLocationTrackingSpec() {
260
266
  override fun getLocationPermissionStatus(): PermissionStatus {
261
267
  val context = NitroModules.applicationContext ?: return PermissionStatus.NOTDETERMINED
262
268
 
263
- val fineGranted = androidx.core.content.ContextCompat.checkSelfPermission(
269
+ val fineGranted = ContextCompat.checkSelfPermission(
264
270
  context, android.Manifest.permission.ACCESS_FINE_LOCATION
265
- ) == android.content.pm.PackageManager.PERMISSION_GRANTED
271
+ ) == PackageManager.PERMISSION_GRANTED
266
272
 
267
273
  if (!fineGranted) {
268
- // Check if we've ever asked — if the app just installed, it's "notDetermined"
269
- // Android doesn't have a direct "notDetermined" state, so we treat
270
- // not-granted as DENIED (the JS side can use requestPermission to prompt)
271
274
  return PermissionStatus.DENIED
272
275
  }
273
276
 
274
277
  // Fine location granted — check background
275
278
  if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q) {
276
- val bgGranted = androidx.core.content.ContextCompat.checkSelfPermission(
279
+ val bgGranted = ContextCompat.checkSelfPermission(
277
280
  context, android.Manifest.permission.ACCESS_BACKGROUND_LOCATION
278
- ) == android.content.pm.PackageManager.PERMISSION_GRANTED
281
+ ) == PackageManager.PERMISSION_GRANTED
279
282
  return if (bgGranted) PermissionStatus.ALWAYS else PermissionStatus.WHENINUSE
280
283
  }
281
284
 
@@ -283,6 +286,79 @@ class NitroLocationTracking : HybridNitroLocationTrackingSpec() {
283
286
  return PermissionStatus.ALWAYS
284
287
  }
285
288
 
289
+ override fun requestLocationPermission(): Promise<PermissionStatus> {
290
+ return Promise.async {
291
+ suspendCoroutine { cont ->
292
+ val context = NitroModules.applicationContext
293
+ if (context == null) {
294
+ cont.resume(PermissionStatus.DENIED)
295
+ return@suspendCoroutine
296
+ }
297
+
298
+ // Already granted — return current status immediately
299
+ val fineGranted = ContextCompat.checkSelfPermission(
300
+ context, android.Manifest.permission.ACCESS_FINE_LOCATION
301
+ ) == PackageManager.PERMISSION_GRANTED
302
+
303
+ if (fineGranted) {
304
+ cont.resume(getLocationPermissionStatus())
305
+ return@suspendCoroutine
306
+ }
307
+
308
+ // Need to request — get the current Activity
309
+ val activity = (context as? ReactContext)?.currentActivity
310
+ if (activity == null) {
311
+ Log.e(TAG, "requestLocationPermission — no current Activity available")
312
+ cont.resume(PermissionStatus.DENIED)
313
+ return@suspendCoroutine
314
+ }
315
+
316
+ // Use PermissionAwareActivity if available (React Native's Activity)
317
+ if (activity is com.facebook.react.modules.core.PermissionAwareActivity) {
318
+ activity.requestPermissions(
319
+ arrayOf(
320
+ android.Manifest.permission.ACCESS_FINE_LOCATION,
321
+ android.Manifest.permission.ACCESS_COARSE_LOCATION
322
+ ),
323
+ PERMISSION_REQUEST_CODE
324
+ ) { requestCode, _, _ ->
325
+ if (requestCode == PERMISSION_REQUEST_CODE) {
326
+ cont.resume(getLocationPermissionStatus())
327
+ }
328
+ true // PermissionListener requires Boolean return
329
+ }
330
+ } else {
331
+ // Fallback: use ActivityCompat (result won't be captured directly)
332
+ ActivityCompat.requestPermissions(
333
+ activity,
334
+ arrayOf(
335
+ android.Manifest.permission.ACCESS_FINE_LOCATION,
336
+ android.Manifest.permission.ACCESS_COARSE_LOCATION
337
+ ),
338
+ PERMISSION_REQUEST_CODE
339
+ )
340
+ // Poll for result after user interacts with the dialog
341
+ android.os.Handler(android.os.Looper.getMainLooper()).postDelayed({
342
+ cont.resume(getLocationPermissionStatus())
343
+ }, 5000)
344
+ }
345
+ }
346
+ }
347
+ }
348
+
349
+ // === Distance Utilities ===
350
+
351
+ override fun getDistanceBetween(lat1: Double, lon1: Double, lat2: Double, lon2: Double): Double {
352
+ val results = FloatArray(1)
353
+ android.location.Location.distanceBetween(lat1, lon1, lat2, lon2, results)
354
+ return results[0].toDouble()
355
+ }
356
+
357
+ override fun getDistanceToGeofence(regionId: String): Double {
358
+ ensureInitialized()
359
+ return geofenceManager?.distanceTo(regionId, locationEngine?.lastLocation) ?: -1.0
360
+ }
361
+
286
362
  // === Notifications ===
287
363
 
288
364
  override fun showLocalNotification(title: String, body: String) {
@@ -62,6 +62,12 @@ class GeofenceManager: NSObject, CLLocationManagerDelegate {
62
62
  }
63
63
  }
64
64
 
65
+ func distanceTo(regionId: String, from location: CLLocation?) -> Double {
66
+ guard let region = activeRegions[regionId], let location = location else { return -1 }
67
+ let center = CLLocation(latitude: region.latitude, longitude: region.longitude)
68
+ return location.distance(from: center)
69
+ }
70
+
65
71
  func destroy() {
66
72
  removeAllGeofences()
67
73
  callback = nil
@@ -11,6 +11,8 @@ class LocationEngine: NSObject, CLLocationManagerDelegate {
11
11
  return mgr
12
12
  }()
13
13
  private var tracking = false
14
+ private var pendingPermissionCompletion: ((CLAuthorizationStatus) -> Void)?
15
+ private var pendingStartAfterPermission = false
14
16
 
15
17
  var onLocation: ((LocationData) -> Void)?
16
18
  var onMotionChange: ((Bool) -> Void)?
@@ -21,6 +23,11 @@ class LocationEngine: NSObject, CLLocationManagerDelegate {
21
23
  let tripCalculator = TripCalculator()
22
24
  var providerStatusCallback: ((LocationProviderStatus, LocationProviderStatus) -> Void)?
23
25
 
26
+ /// The most recently received location from Core Location (for distance calculations)
27
+ var lastCLLocation: CLLocation? {
28
+ return locationManager.location
29
+ }
30
+
24
31
  override init() {
25
32
  super.init()
26
33
  locationManager.delegate = self
@@ -45,6 +52,7 @@ class LocationEngine: NSObject, CLLocationManagerDelegate {
45
52
  func start() {
46
53
  guard CLLocationManager.authorizationStatus() == .authorizedAlways ||
47
54
  CLLocationManager.authorizationStatus() == .authorizedWhenInUse else {
55
+ pendingStartAfterPermission = true
48
56
  locationManager.requestAlwaysAuthorization()
49
57
  return
50
58
  }
@@ -52,10 +60,21 @@ class LocationEngine: NSObject, CLLocationManagerDelegate {
52
60
  tracking = true
53
61
  }
54
62
 
63
+ func requestPermission(completion: @escaping (CLAuthorizationStatus) -> Void) {
64
+ let currentStatus = CLLocationManager.authorizationStatus()
65
+ if currentStatus != .notDetermined {
66
+ completion(currentStatus)
67
+ return
68
+ }
69
+ pendingPermissionCompletion = completion
70
+ locationManager.requestAlwaysAuthorization()
71
+ }
72
+
55
73
  func stop() {
56
74
  locationManager.stopUpdatingLocation()
57
75
  tracking = false
58
76
  }
77
+
59
78
 
60
79
  var isTracking: Bool { tracking }
61
80
 
@@ -80,11 +99,11 @@ class LocationEngine: NSObject, CLLocationManagerDelegate {
80
99
  }
81
100
  // Use a SEPARATE manager for one-shot requests so we never
82
101
  // stop the continuous startUpdatingLocation() on locationManager.
83
- pendingLocationCompletion = completion
102
+ pendingLocationCompletions.append(completion)
84
103
  oneShotManager.requestLocation()
85
104
  }
86
105
 
87
- private var pendingLocationCompletion: ((LocationData?) -> Void)?
106
+ private var pendingLocationCompletions: [(LocationData?) -> Void] = []
88
107
 
89
108
  func locationManager(_ manager: CLLocationManager,
90
109
  didUpdateLocations locations: [CLLocation]) {
@@ -104,9 +123,12 @@ class LocationEngine: NSObject, CLLocationManagerDelegate {
104
123
  )
105
124
 
106
125
  // Handle pending one-shot request (from oneShotManager)
107
- if manager === oneShotManager, let completion = pendingLocationCompletion {
108
- completion(data)
109
- pendingLocationCompletion = nil
126
+ if manager === oneShotManager {
127
+ let completions = pendingLocationCompletions
128
+ pendingLocationCompletions.removeAll()
129
+ for completion in completions {
130
+ completion(data)
131
+ }
110
132
  return
111
133
  }
112
134
 
@@ -131,9 +153,12 @@ class LocationEngine: NSObject, CLLocationManagerDelegate {
131
153
 
132
154
  func locationManager(_ manager: CLLocationManager,
133
155
  didFailWithError error: Error) {
134
- if manager === oneShotManager, let completion = pendingLocationCompletion {
135
- completion(nil)
136
- pendingLocationCompletion = nil
156
+ if manager === oneShotManager {
157
+ let completions = pendingLocationCompletions
158
+ pendingLocationCompletions.removeAll()
159
+ for completion in completions {
160
+ completion(nil)
161
+ }
137
162
  }
138
163
  }
139
164
 
@@ -169,6 +194,24 @@ class LocationEngine: NSObject, CLLocationManagerDelegate {
169
194
 
170
195
  func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) {
171
196
  guard manager === locationManager else { return }
197
+
198
+ let authStatus = CLLocationManager.authorizationStatus()
199
+
200
+ // Resolve pending permission request
201
+ if let completion = pendingPermissionCompletion {
202
+ pendingPermissionCompletion = nil
203
+ completion(authStatus)
204
+ }
205
+
206
+ // Auto-start tracking if permission was granted after start() was called
207
+ if pendingStartAfterPermission {
208
+ pendingStartAfterPermission = false
209
+ if authStatus == .authorizedAlways || authStatus == .authorizedWhenInUse {
210
+ locationManager.startUpdatingLocation()
211
+ tracking = true
212
+ }
213
+ }
214
+
172
215
  let enabled = CLLocationManager.locationServicesEnabled()
173
216
  let status: LocationProviderStatus = enabled ? .enabled : .disabled
174
217
  providerStatusCallback?(status, status)
@@ -3,7 +3,6 @@ import CoreLocation
3
3
  import NitroModules
4
4
 
5
5
  class NitroLocationTracking: HybridNitroLocationTrackingSpec {
6
-
7
6
  private let locationEngine = LocationEngine()
8
7
  private let connectionManager = ConnectionManager()
9
8
  private let dbWriter = NativeDBWriter()
@@ -17,6 +16,7 @@ class NitroLocationTracking: HybridNitroLocationTrackingSpec {
17
16
  private var geofenceCallback: ((GeofenceEvent, String) -> Void)?
18
17
  private var speedAlertCallback: ((SpeedAlertType, Double) -> Void)?
19
18
  private var providerStatusCallback: ((LocationProviderStatus, LocationProviderStatus) -> Void)?
19
+ private var permissionPromise: Promise<PermissionStatus>?
20
20
 
21
21
  override init() {
22
22
  super.init()
@@ -44,6 +44,7 @@ class NitroLocationTracking: HybridNitroLocationTrackingSpec {
44
44
  locationEngine.stop()
45
45
  }
46
46
 
47
+
47
48
  func getCurrentLocation() throws -> Promise<LocationData> {
48
49
  let promise = Promise<LocationData>()
49
50
  locationEngine.getCurrentLocation { data in
@@ -58,7 +59,7 @@ class NitroLocationTracking: HybridNitroLocationTrackingSpec {
58
59
  return promise
59
60
  }
60
61
 
61
- func isTracking() throws -> Bool {
62
+ func isTracking() throws -> Bool {
62
63
  return locationEngine.isTracking
63
64
  }
64
65
 
@@ -212,6 +213,41 @@ class NitroLocationTracking: HybridNitroLocationTrackingSpec {
212
213
  }
213
214
  }
214
215
 
216
+ func requestLocationPermission() throws -> Promise<PermissionStatus> {
217
+ let promise = Promise<PermissionStatus>()
218
+ locationEngine.requestPermission { authStatus in
219
+ let result: PermissionStatus
220
+ switch authStatus {
221
+ case .notDetermined:
222
+ result = .notdetermined
223
+ case .restricted:
224
+ result = .restricted
225
+ case .denied:
226
+ result = .denied
227
+ case .authorizedWhenInUse:
228
+ result = .wheninuse
229
+ case .authorizedAlways:
230
+ result = .always
231
+ @unknown default:
232
+ result = .notdetermined
233
+ }
234
+ promise.resolve(withResult: result)
235
+ }
236
+ return promise
237
+ }
238
+
239
+ // MARK: - Distance Utilities
240
+
241
+ func getDistanceBetween(lat1: Double, lon1: Double, lat2: Double, lon2: Double) throws -> Double {
242
+ let loc1 = CLLocation(latitude: lat1, longitude: lon1)
243
+ let loc2 = CLLocation(latitude: lat2, longitude: lon2)
244
+ return loc1.distance(from: loc2)
245
+ }
246
+
247
+ func getDistanceToGeofence(regionId: String) throws -> Double {
248
+ return geofenceManager.distanceTo(regionId: regionId, from: locationEngine.lastCLLocation)
249
+ }
250
+
215
251
  // MARK: - Notifications
216
252
 
217
253
  func showLocalNotification(title: String, body: String) throws {
@@ -96,6 +96,9 @@ export interface NitroLocationTracking extends HybridObject<{
96
96
  isLocationServicesEnabled(): boolean;
97
97
  onProviderStatusChange(callback: ProviderStatusCallback): void;
98
98
  getLocationPermissionStatus(): PermissionStatus;
99
+ requestLocationPermission(): Promise<PermissionStatus>;
100
+ getDistanceBetween(lat1: number, lon1: number, lat2: number, lon2: number): number;
101
+ getDistanceToGeofence(regionId: string): number;
99
102
  showLocalNotification(title: string, body: string): void;
100
103
  updateForegroundNotification(title: string, body: string): void;
101
104
  destroy(): void;
@@ -1 +1 @@
1
- {"version":3,"file":"NitroLocationTracking.nitro.d.ts","sourceRoot":"","sources":["../../../src/NitroLocationTracking.nitro.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAI/D,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,UAAU,GAAG,KAAK,CAAC;AACxD,MAAM,MAAM,eAAe,GAAG,WAAW,GAAG,cAAc,GAAG,cAAc,CAAC;AAI5E,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,MAAM,WAAW,cAAc;IAC7B,eAAe,EAAE,aAAa,CAAC;IAC/B,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,OAAO,CAAC;IACzB,WAAW,EAAE,OAAO,CAAC;IACrB,2BAA2B,EAAE,MAAM,CAAC;IACpC,0BAA0B,EAAE,MAAM,CAAC;CACpC;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,oBAAoB,EAAE,MAAM,CAAC;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,MAAM,gBAAgB,GAAG,CAAC,QAAQ,EAAE,YAAY,KAAK,IAAI,CAAC;AAChE,MAAM,MAAM,uBAAuB,GAAG,CAAC,KAAK,EAAE,eAAe,KAAK,IAAI,CAAC;AACvE,MAAM,MAAM,eAAe,GAAG,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;AAExD,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,EAAE,OAAO,CAAC;IACvB,YAAY,EAAE,OAAO,CAAC;CACvB;AAED,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG,MAAM,CAAC;AAC7C,MAAM,MAAM,gBAAgB,GAAG,CAAC,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;AAEhF,MAAM,WAAW,WAAW;IAC1B,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,MAAM,cAAc,GAAG,UAAU,GAAG,YAAY,GAAG,eAAe,CAAC;AACzE,MAAM,MAAM,kBAAkB,GAAG,CAC/B,KAAK,EAAE,cAAc,EACrB,eAAe,EAAE,MAAM,KACpB,IAAI,CAAC;AAEV,MAAM,WAAW,SAAS;IACxB,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,eAAe,EAAE,MAAM,CAAC;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,MAAM,sBAAsB,GAAG,SAAS,GAAG,UAAU,CAAC;AAC5D,MAAM,MAAM,sBAAsB,GAAG,CACnC,GAAG,EAAE,sBAAsB,EAC3B,OAAO,EAAE,sBAAsB,KAC5B,IAAI,CAAC;AAEV,MAAM,MAAM,gBAAgB,GACxB,eAAe,GACf,QAAQ,GACR,YAAY,GACZ,WAAW,GACX,QAAQ,CAAC;AAIb,MAAM,WAAW,qBACf,SAAQ,YAAY,CAAC;IAAE,GAAG,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,QAAQ,CAAA;CAAE,CAAC;IAEzD,SAAS,CAAC,MAAM,EAAE,cAAc,GAAG,IAAI,CAAC;IACxC,aAAa,IAAI,IAAI,CAAC;IACtB,YAAY,IAAI,IAAI,CAAC;IACrB,kBAAkB,IAAI,OAAO,CAAC,YAAY,CAAC,CAAC;IAC5C,UAAU,IAAI,OAAO,CAAC;IAEtB,UAAU,CAAC,QAAQ,EAAE,gBAAgB,GAAG,IAAI,CAAC;IAC7C,cAAc,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE,OAAO,KAAK,IAAI,GAAG,IAAI,CAAC;IAG5D,mBAAmB,CAAC,MAAM,EAAE,gBAAgB,GAAG,IAAI,CAAC;IACpD,gBAAgB,IAAI,IAAI,CAAC;IACzB,mBAAmB,IAAI,IAAI,CAAC;IAC5B,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,kBAAkB,IAAI,eAAe,CAAC;IAEtC,uBAAuB,CAAC,QAAQ,EAAE,uBAAuB,GAAG,IAAI,CAAC;IACjE,SAAS,CAAC,QAAQ,EAAE,eAAe,GAAG,IAAI,CAAC;IAG3C,SAAS,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;IAG9B,gBAAgB,IAAI,OAAO,CAAC;IAC5B,sBAAsB,CAAC,MAAM,EAAE,OAAO,GAAG,IAAI,CAAC;IAG9C,WAAW,CAAC,MAAM,EAAE,cAAc,GAAG,IAAI,CAAC;IAC1C,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACvC,kBAAkB,IAAI,IAAI,CAAC;IAC3B,eAAe,CAAC,QAAQ,EAAE,gBAAgB,GAAG,IAAI,CAAC;IAGlD,qBAAqB,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI,CAAC;IACjD,YAAY,CAAC,QAAQ,EAAE,kBAAkB,GAAG,IAAI,CAAC;IACjD,eAAe,IAAI,MAAM,CAAC;IAG1B,oBAAoB,IAAI,IAAI,CAAC;IAC7B,mBAAmB,IAAI,SAAS,CAAC;IACjC,YAAY,IAAI,SAAS,CAAC;IAC1B,oBAAoB,IAAI,IAAI,CAAC;IAG7B,yBAAyB,IAAI,OAAO,CAAC;IACrC,sBAAsB,CAAC,QAAQ,EAAE,sBAAsB,GAAG,IAAI,CAAC;IAG/D,2BAA2B,IAAI,gBAAgB,CAAC;IAGhD,qBAAqB,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACzD,4BAA4B,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAGhE,OAAO,IAAI,IAAI,CAAC;CACjB"}
1
+ {"version":3,"file":"NitroLocationTracking.nitro.d.ts","sourceRoot":"","sources":["../../../src/NitroLocationTracking.nitro.ts"],"names":[],"mappings":"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"}
@@ -265,6 +265,32 @@ namespace margelo::nitro::nitrolocationtracking {
265
265
  auto __result = method(_javaPart);
266
266
  return __result->toCpp();
267
267
  }
268
+ std::shared_ptr<Promise<PermissionStatus>> JHybridNitroLocationTrackingSpec::requestLocationPermission() {
269
+ static const auto method = javaClassStatic()->getMethod<jni::local_ref<JPromise::javaobject>()>("requestLocationPermission");
270
+ auto __result = method(_javaPart);
271
+ return [&]() {
272
+ auto __promise = Promise<PermissionStatus>::create();
273
+ __result->cthis()->addOnResolvedListener([=](const jni::alias_ref<jni::JObject>& __boxedResult) {
274
+ auto __result = jni::static_ref_cast<JPermissionStatus>(__boxedResult);
275
+ __promise->resolve(__result->toCpp());
276
+ });
277
+ __result->cthis()->addOnRejectedListener([=](const jni::alias_ref<jni::JThrowable>& __throwable) {
278
+ jni::JniException __jniError(__throwable);
279
+ __promise->reject(std::make_exception_ptr(__jniError));
280
+ });
281
+ return __promise;
282
+ }();
283
+ }
284
+ double JHybridNitroLocationTrackingSpec::getDistanceBetween(double lat1, double lon1, double lat2, double lon2) {
285
+ static const auto method = javaClassStatic()->getMethod<double(double /* lat1 */, double /* lon1 */, double /* lat2 */, double /* lon2 */)>("getDistanceBetween");
286
+ auto __result = method(_javaPart, lat1, lon1, lat2, lon2);
287
+ return __result;
288
+ }
289
+ double JHybridNitroLocationTrackingSpec::getDistanceToGeofence(const std::string& regionId) {
290
+ static const auto method = javaClassStatic()->getMethod<double(jni::alias_ref<jni::JString> /* regionId */)>("getDistanceToGeofence");
291
+ auto __result = method(_javaPart, jni::make_jstring(regionId));
292
+ return __result;
293
+ }
268
294
  void JHybridNitroLocationTrackingSpec::showLocalNotification(const std::string& title, const std::string& body) {
269
295
  static const auto method = javaClassStatic()->getMethod<void(jni::alias_ref<jni::JString> /* title */, jni::alias_ref<jni::JString> /* body */)>("showLocalNotification");
270
296
  method(_javaPart, jni::make_jstring(title), jni::make_jstring(body));
@@ -86,6 +86,9 @@ namespace margelo::nitro::nitrolocationtracking {
86
86
  bool isLocationServicesEnabled() override;
87
87
  void onProviderStatusChange(const std::function<void(LocationProviderStatus /* gps */, LocationProviderStatus /* network */)>& callback) override;
88
88
  PermissionStatus getLocationPermissionStatus() override;
89
+ std::shared_ptr<Promise<PermissionStatus>> requestLocationPermission() override;
90
+ double getDistanceBetween(double lat1, double lon1, double lat2, double lon2) override;
91
+ double getDistanceToGeofence(const std::string& regionId) override;
89
92
  void showLocalNotification(const std::string& title, const std::string& body) override;
90
93
  void updateForegroundNotification(const std::string& title, const std::string& body) override;
91
94
  void destroy() override;
@@ -205,6 +205,18 @@ abstract class HybridNitroLocationTrackingSpec: HybridObject() {
205
205
  @Keep
206
206
  abstract fun getLocationPermissionStatus(): PermissionStatus
207
207
 
208
+ @DoNotStrip
209
+ @Keep
210
+ abstract fun requestLocationPermission(): Promise<PermissionStatus>
211
+
212
+ @DoNotStrip
213
+ @Keep
214
+ abstract fun getDistanceBetween(lat1: Double, lon1: Double, lat2: Double, lon2: Double): Double
215
+
216
+ @DoNotStrip
217
+ @Keep
218
+ abstract fun getDistanceToGeofence(regionId: String): Double
219
+
208
220
  @DoNotStrip
209
221
  @Keep
210
222
  abstract fun showLocalNotification(title: String, body: String): Unit
@@ -78,6 +78,14 @@ namespace margelo::nitro::nitrolocationtracking::bridge::swift {
78
78
  };
79
79
  }
80
80
 
81
+ // pragma MARK: std::function<void(PermissionStatus /* result */)>
82
+ Func_void_PermissionStatus create_Func_void_PermissionStatus(void* NON_NULL swiftClosureWrapper) noexcept {
83
+ auto swiftClosure = NitroLocationTracking::Func_void_PermissionStatus::fromUnsafe(swiftClosureWrapper);
84
+ return [swiftClosure = std::move(swiftClosure)](PermissionStatus result) mutable -> void {
85
+ swiftClosure.call(static_cast<int>(result));
86
+ };
87
+ }
88
+
81
89
  // pragma MARK: std::shared_ptr<HybridNitroLocationTrackingSpec>
82
90
  std::shared_ptr<HybridNitroLocationTrackingSpec> create_std__shared_ptr_HybridNitroLocationTrackingSpec_(void* NON_NULL swiftUnsafePointer) noexcept {
83
91
  NitroLocationTracking::HybridNitroLocationTrackingSpec_cxx swiftPart = NitroLocationTracking::HybridNitroLocationTrackingSpec_cxx::fromUnsafe(swiftUnsafePointer);
@@ -268,6 +268,40 @@ namespace margelo::nitro::nitrolocationtracking::bridge::swift {
268
268
  return Func_void_LocationProviderStatus_LocationProviderStatus_Wrapper(std::move(value));
269
269
  }
270
270
 
271
+ // pragma MARK: std::shared_ptr<Promise<PermissionStatus>>
272
+ /**
273
+ * Specialized version of `std::shared_ptr<Promise<PermissionStatus>>`.
274
+ */
275
+ using std__shared_ptr_Promise_PermissionStatus__ = std::shared_ptr<Promise<PermissionStatus>>;
276
+ inline std::shared_ptr<Promise<PermissionStatus>> create_std__shared_ptr_Promise_PermissionStatus__() noexcept {
277
+ return Promise<PermissionStatus>::create();
278
+ }
279
+ inline PromiseHolder<PermissionStatus> wrap_std__shared_ptr_Promise_PermissionStatus__(std::shared_ptr<Promise<PermissionStatus>> promise) noexcept {
280
+ return PromiseHolder<PermissionStatus>(std::move(promise));
281
+ }
282
+
283
+ // pragma MARK: std::function<void(PermissionStatus /* result */)>
284
+ /**
285
+ * Specialized version of `std::function<void(PermissionStatus)>`.
286
+ */
287
+ using Func_void_PermissionStatus = std::function<void(PermissionStatus /* result */)>;
288
+ /**
289
+ * Wrapper class for a `std::function<void(PermissionStatus / * result * /)>`, this can be used from Swift.
290
+ */
291
+ class Func_void_PermissionStatus_Wrapper final {
292
+ public:
293
+ explicit Func_void_PermissionStatus_Wrapper(std::function<void(PermissionStatus /* result */)>&& func): _function(std::make_unique<std::function<void(PermissionStatus /* result */)>>(std::move(func))) {}
294
+ inline void call(int result) const noexcept {
295
+ _function->operator()(static_cast<PermissionStatus>(result));
296
+ }
297
+ private:
298
+ std::unique_ptr<std::function<void(PermissionStatus /* result */)>> _function;
299
+ } SWIFT_NONCOPYABLE;
300
+ Func_void_PermissionStatus create_Func_void_PermissionStatus(void* NON_NULL swiftClosureWrapper) noexcept;
301
+ inline Func_void_PermissionStatus_Wrapper wrap_Func_void_PermissionStatus(Func_void_PermissionStatus value) noexcept {
302
+ return Func_void_PermissionStatus_Wrapper(std::move(value));
303
+ }
304
+
271
305
  // pragma MARK: std::shared_ptr<HybridNitroLocationTrackingSpec>
272
306
  /**
273
307
  * Specialized version of `std::shared_ptr<HybridNitroLocationTrackingSpec>`.
@@ -351,5 +385,14 @@ namespace margelo::nitro::nitrolocationtracking::bridge::swift {
351
385
  inline Result_PermissionStatus_ create_Result_PermissionStatus_(const std::exception_ptr& error) noexcept {
352
386
  return Result<PermissionStatus>::withError(error);
353
387
  }
388
+
389
+ // pragma MARK: Result<std::shared_ptr<Promise<PermissionStatus>>>
390
+ using Result_std__shared_ptr_Promise_PermissionStatus___ = Result<std::shared_ptr<Promise<PermissionStatus>>>;
391
+ inline Result_std__shared_ptr_Promise_PermissionStatus___ create_Result_std__shared_ptr_Promise_PermissionStatus___(const std::shared_ptr<Promise<PermissionStatus>>& value) noexcept {
392
+ return Result<std::shared_ptr<Promise<PermissionStatus>>>::withValue(value);
393
+ }
394
+ inline Result_std__shared_ptr_Promise_PermissionStatus___ create_Result_std__shared_ptr_Promise_PermissionStatus___(const std::exception_ptr& error) noexcept {
395
+ return Result<std::shared_ptr<Promise<PermissionStatus>>>::withError(error);
396
+ }
354
397
 
355
398
  } // namespace margelo::nitro::nitrolocationtracking::bridge::swift
@@ -310,6 +310,30 @@ namespace margelo::nitro::nitrolocationtracking {
310
310
  auto __value = std::move(__result.value());
311
311
  return __value;
312
312
  }
313
+ inline std::shared_ptr<Promise<PermissionStatus>> requestLocationPermission() override {
314
+ auto __result = _swiftPart.requestLocationPermission();
315
+ if (__result.hasError()) [[unlikely]] {
316
+ std::rethrow_exception(__result.error());
317
+ }
318
+ auto __value = std::move(__result.value());
319
+ return __value;
320
+ }
321
+ inline double getDistanceBetween(double lat1, double lon1, double lat2, double lon2) override {
322
+ auto __result = _swiftPart.getDistanceBetween(std::forward<decltype(lat1)>(lat1), std::forward<decltype(lon1)>(lon1), std::forward<decltype(lat2)>(lat2), std::forward<decltype(lon2)>(lon2));
323
+ if (__result.hasError()) [[unlikely]] {
324
+ std::rethrow_exception(__result.error());
325
+ }
326
+ auto __value = std::move(__result.value());
327
+ return __value;
328
+ }
329
+ inline double getDistanceToGeofence(const std::string& regionId) override {
330
+ auto __result = _swiftPart.getDistanceToGeofence(regionId);
331
+ if (__result.hasError()) [[unlikely]] {
332
+ std::rethrow_exception(__result.error());
333
+ }
334
+ auto __value = std::move(__result.value());
335
+ return __value;
336
+ }
313
337
  inline void showLocalNotification(const std::string& title, const std::string& body) override {
314
338
  auto __result = _swiftPart.showLocalNotification(title, body);
315
339
  if (__result.hasError()) [[unlikely]] {
@@ -0,0 +1,46 @@
1
+ ///
2
+ /// Func_void_PermissionStatus.swift
3
+ /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
4
+ /// https://github.com/mrousavy/nitro
5
+ /// Copyright © Marc Rousavy @ Margelo
6
+ ///
7
+
8
+ import NitroModules
9
+
10
+ /**
11
+ * Wraps a Swift `(_ value: PermissionStatus) -> Void` as a class.
12
+ * This class can be used from C++, e.g. to wrap the Swift closure as a `std::function`.
13
+ */
14
+ public final class Func_void_PermissionStatus {
15
+ public typealias bridge = margelo.nitro.nitrolocationtracking.bridge.swift
16
+
17
+ private let closure: (_ value: PermissionStatus) -> Void
18
+
19
+ public init(_ closure: @escaping (_ value: PermissionStatus) -> Void) {
20
+ self.closure = closure
21
+ }
22
+
23
+ @inline(__always)
24
+ public func call(value: Int32) -> Void {
25
+ self.closure(margelo.nitro.nitrolocationtracking.PermissionStatus(rawValue: value)!)
26
+ }
27
+
28
+ /**
29
+ * Casts this instance to a retained unsafe raw pointer.
30
+ * This acquires one additional strong reference on the object!
31
+ */
32
+ @inline(__always)
33
+ public func toUnsafe() -> UnsafeMutableRawPointer {
34
+ return Unmanaged.passRetained(self).toOpaque()
35
+ }
36
+
37
+ /**
38
+ * Casts an unsafe pointer to a `Func_void_PermissionStatus`.
39
+ * The pointer has to be a retained opaque `Unmanaged<Func_void_PermissionStatus>`.
40
+ * This removes one strong reference from the object!
41
+ */
42
+ @inline(__always)
43
+ public static func fromUnsafe(_ pointer: UnsafeMutableRawPointer) -> Func_void_PermissionStatus {
44
+ return Unmanaged<Func_void_PermissionStatus>.fromOpaque(pointer).takeRetainedValue()
45
+ }
46
+ }
@@ -44,6 +44,9 @@ public protocol HybridNitroLocationTrackingSpec_protocol: HybridObject {
44
44
  func isLocationServicesEnabled() throws -> Bool
45
45
  func onProviderStatusChange(callback: @escaping (_ gps: LocationProviderStatus, _ network: LocationProviderStatus) -> Void) throws -> Void
46
46
  func getLocationPermissionStatus() throws -> PermissionStatus
47
+ func requestLocationPermission() throws -> Promise<PermissionStatus>
48
+ func getDistanceBetween(lat1: Double, lon1: Double, lat2: Double, lon2: Double) throws -> Double
49
+ func getDistanceToGeofence(regionId: String) throws -> Double
47
50
  func showLocalNotification(title: String, body: String) throws -> Void
48
51
  func updateForegroundNotification(title: String, body: String) throws -> Void
49
52
  func destroy() throws -> Void
@@ -524,6 +524,49 @@ open class HybridNitroLocationTrackingSpec_cxx {
524
524
  }
525
525
  }
526
526
 
527
+ @inline(__always)
528
+ public final func requestLocationPermission() -> bridge.Result_std__shared_ptr_Promise_PermissionStatus___ {
529
+ do {
530
+ let __result = try self.__implementation.requestLocationPermission()
531
+ let __resultCpp = { () -> bridge.std__shared_ptr_Promise_PermissionStatus__ in
532
+ let __promise = bridge.create_std__shared_ptr_Promise_PermissionStatus__()
533
+ let __promiseHolder = bridge.wrap_std__shared_ptr_Promise_PermissionStatus__(__promise)
534
+ __result
535
+ .then({ __result in __promiseHolder.resolve(__result) })
536
+ .catch({ __error in __promiseHolder.reject(__error.toCpp()) })
537
+ return __promise
538
+ }()
539
+ return bridge.create_Result_std__shared_ptr_Promise_PermissionStatus___(__resultCpp)
540
+ } catch (let __error) {
541
+ let __exceptionPtr = __error.toCpp()
542
+ return bridge.create_Result_std__shared_ptr_Promise_PermissionStatus___(__exceptionPtr)
543
+ }
544
+ }
545
+
546
+ @inline(__always)
547
+ public final func getDistanceBetween(lat1: Double, lon1: Double, lat2: Double, lon2: Double) -> bridge.Result_double_ {
548
+ do {
549
+ let __result = try self.__implementation.getDistanceBetween(lat1: lat1, lon1: lon1, lat2: lat2, lon2: lon2)
550
+ let __resultCpp = __result
551
+ return bridge.create_Result_double_(__resultCpp)
552
+ } catch (let __error) {
553
+ let __exceptionPtr = __error.toCpp()
554
+ return bridge.create_Result_double_(__exceptionPtr)
555
+ }
556
+ }
557
+
558
+ @inline(__always)
559
+ public final func getDistanceToGeofence(regionId: std.string) -> bridge.Result_double_ {
560
+ do {
561
+ let __result = try self.__implementation.getDistanceToGeofence(regionId: String(regionId))
562
+ let __resultCpp = __result
563
+ return bridge.create_Result_double_(__resultCpp)
564
+ } catch (let __error) {
565
+ let __exceptionPtr = __error.toCpp()
566
+ return bridge.create_Result_double_(__exceptionPtr)
567
+ }
568
+ }
569
+
527
570
  @inline(__always)
528
571
  public final func showLocalNotification(title: std.string, body: std.string) -> bridge.Result_void_ {
529
572
  do {
@@ -45,6 +45,9 @@ namespace margelo::nitro::nitrolocationtracking {
45
45
  prototype.registerHybridMethod("isLocationServicesEnabled", &HybridNitroLocationTrackingSpec::isLocationServicesEnabled);
46
46
  prototype.registerHybridMethod("onProviderStatusChange", &HybridNitroLocationTrackingSpec::onProviderStatusChange);
47
47
  prototype.registerHybridMethod("getLocationPermissionStatus", &HybridNitroLocationTrackingSpec::getLocationPermissionStatus);
48
+ prototype.registerHybridMethod("requestLocationPermission", &HybridNitroLocationTrackingSpec::requestLocationPermission);
49
+ prototype.registerHybridMethod("getDistanceBetween", &HybridNitroLocationTrackingSpec::getDistanceBetween);
50
+ prototype.registerHybridMethod("getDistanceToGeofence", &HybridNitroLocationTrackingSpec::getDistanceToGeofence);
48
51
  prototype.registerHybridMethod("showLocalNotification", &HybridNitroLocationTrackingSpec::showLocalNotification);
49
52
  prototype.registerHybridMethod("updateForegroundNotification", &HybridNitroLocationTrackingSpec::updateForegroundNotification);
50
53
  prototype.registerHybridMethod("destroy", &HybridNitroLocationTrackingSpec::destroy);
@@ -113,6 +113,9 @@ namespace margelo::nitro::nitrolocationtracking {
113
113
  virtual bool isLocationServicesEnabled() = 0;
114
114
  virtual void onProviderStatusChange(const std::function<void(LocationProviderStatus /* gps */, LocationProviderStatus /* network */)>& callback) = 0;
115
115
  virtual PermissionStatus getLocationPermissionStatus() = 0;
116
+ virtual std::shared_ptr<Promise<PermissionStatus>> requestLocationPermission() = 0;
117
+ virtual double getDistanceBetween(double lat1, double lon1, double lat2, double lon2) = 0;
118
+ virtual double getDistanceToGeofence(const std::string& regionId) = 0;
116
119
  virtual void showLocalNotification(const std::string& title, const std::string& body) = 0;
117
120
  virtual void updateForegroundNotification(const std::string& title, const std::string& body) = 0;
118
121
  virtual void destroy() = 0;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-nitro-location-tracking",
3
- "version": "0.1.7",
3
+ "version": "0.1.9",
4
4
  "description": "A React Native Nitro module for location tracking",
5
5
  "main": "./lib/module/index.js",
6
6
  "types": "./lib/typescript/src/index.d.ts",
@@ -143,6 +143,16 @@ export interface NitroLocationTracking
143
143
 
144
144
  // === Permission Status ===
145
145
  getLocationPermissionStatus(): PermissionStatus;
146
+ requestLocationPermission(): Promise<PermissionStatus>;
147
+
148
+ // === Distance Utilities ===
149
+ getDistanceBetween(
150
+ lat1: number,
151
+ lon1: number,
152
+ lat2: number,
153
+ lon2: number
154
+ ): number; // meters
155
+ getDistanceToGeofence(regionId: string): number; // meters from last known location to geofence center, -1 if not found
146
156
 
147
157
  // === Notifications ===
148
158
  showLocalNotification(title: string, body: string): void;