react-native-nitro-location-tracking 0.1.5 → 0.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +677 -7
- package/android/src/main/java/com/margelo/nitro/nitrolocationtracking/GeofenceManager.kt +148 -0
- package/android/src/main/java/com/margelo/nitro/nitrolocationtracking/LocationEngine.kt +55 -1
- package/android/src/main/java/com/margelo/nitro/nitrolocationtracking/NitroLocationTracking.kt +127 -0
- package/android/src/main/java/com/margelo/nitro/nitrolocationtracking/ProviderStatusMonitor.kt +73 -0
- package/android/src/main/java/com/margelo/nitro/nitrolocationtracking/SpeedMonitor.kt +38 -0
- package/android/src/main/java/com/margelo/nitro/nitrolocationtracking/TripCalculator.kt +85 -0
- package/ios/GeofenceManager.swift +69 -0
- package/ios/LocationEngine.swift +56 -2
- package/ios/NitroLocationTracking.swift +104 -0
- package/ios/SpeedMonitor.swift +48 -0
- package/ios/TripCalculator.swift +93 -0
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/src/NitroLocationTracking.nitro.d.ts +44 -0
- package/lib/typescript/src/NitroLocationTracking.nitro.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +1 -1
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/test.d.ts +1 -0
- package/lib/typescript/test.d.ts.map +1 -0
- package/nitrogen/generated/android/c++/JFunc_void_GeofenceEvent_std__string.hpp +78 -0
- package/nitrogen/generated/android/c++/JFunc_void_LocationData.hpp +1 -0
- package/nitrogen/generated/android/c++/JFunc_void_LocationProviderStatus_LocationProviderStatus.hpp +77 -0
- package/nitrogen/generated/android/c++/JFunc_void_SpeedAlertType_double.hpp +77 -0
- package/nitrogen/generated/android/c++/JGeofenceEvent.hpp +58 -0
- package/nitrogen/generated/android/c++/JGeofenceRegion.hpp +77 -0
- package/nitrogen/generated/android/c++/JHybridNitroLocationTrackingSpec.cpp +102 -0
- package/nitrogen/generated/android/c++/JHybridNitroLocationTrackingSpec.hpp +16 -0
- package/nitrogen/generated/android/c++/JLocationData.hpp +8 -4
- package/nitrogen/generated/android/c++/JLocationProviderStatus.hpp +58 -0
- package/nitrogen/generated/android/c++/JPermissionStatus.hpp +67 -0
- package/nitrogen/generated/android/c++/JSpeedAlertType.hpp +61 -0
- package/nitrogen/generated/android/c++/JSpeedConfig.hpp +65 -0
- package/nitrogen/generated/android/c++/JTripStats.hpp +73 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrolocationtracking/Func_void_GeofenceEvent_std__string.kt +80 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrolocationtracking/Func_void_LocationProviderStatus_LocationProviderStatus.kt +80 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrolocationtracking/Func_void_SpeedAlertType_double.kt +80 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrolocationtracking/GeofenceEvent.kt +23 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrolocationtracking/GeofenceRegion.kt +53 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrolocationtracking/HybridNitroLocationTrackingSpec.kt +79 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrolocationtracking/LocationData.kt +6 -3
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrolocationtracking/LocationProviderStatus.kt +23 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrolocationtracking/PermissionStatus.kt +26 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrolocationtracking/SpeedAlertType.kt +24 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrolocationtracking/SpeedConfig.kt +44 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrolocationtracking/TripStats.kt +50 -0
- package/nitrogen/generated/android/nitrolocationtrackingOnLoad.cpp +6 -0
- package/nitrogen/generated/ios/NitroLocationTracking-Swift-Cxx-Bridge.cpp +24 -0
- package/nitrogen/generated/ios/NitroLocationTracking-Swift-Cxx-Bridge.hpp +124 -0
- package/nitrogen/generated/ios/NitroLocationTracking-Swift-Cxx-Umbrella.hpp +22 -0
- package/nitrogen/generated/ios/c++/HybridNitroLocationTrackingSpecSwift.hpp +130 -0
- package/nitrogen/generated/ios/swift/Func_void_GeofenceEvent_std__string.swift +46 -0
- package/nitrogen/generated/ios/swift/Func_void_LocationProviderStatus_LocationProviderStatus.swift +46 -0
- package/nitrogen/generated/ios/swift/Func_void_SpeedAlertType_double.swift +46 -0
- package/nitrogen/generated/ios/swift/GeofenceEvent.swift +40 -0
- package/nitrogen/generated/ios/swift/GeofenceRegion.swift +54 -0
- package/nitrogen/generated/ios/swift/HybridNitroLocationTrackingSpec.swift +16 -0
- package/nitrogen/generated/ios/swift/HybridNitroLocationTrackingSpec_cxx.swift +197 -0
- package/nitrogen/generated/ios/swift/LocationData.swift +20 -2
- package/nitrogen/generated/ios/swift/LocationProviderStatus.swift +40 -0
- package/nitrogen/generated/ios/swift/PermissionStatus.swift +52 -0
- package/nitrogen/generated/ios/swift/SpeedAlertType.swift +44 -0
- package/nitrogen/generated/ios/swift/SpeedConfig.swift +39 -0
- package/nitrogen/generated/ios/swift/TripStats.swift +49 -0
- package/nitrogen/generated/shared/c++/GeofenceEvent.hpp +76 -0
- package/nitrogen/generated/shared/c++/GeofenceRegion.hpp +103 -0
- package/nitrogen/generated/shared/c++/HybridNitroLocationTrackingSpec.cpp +16 -0
- package/nitrogen/generated/shared/c++/HybridNitroLocationTrackingSpec.hpp +37 -0
- package/nitrogen/generated/shared/c++/LocationData.hpp +7 -3
- package/nitrogen/generated/shared/c++/LocationProviderStatus.hpp +76 -0
- package/nitrogen/generated/shared/c++/PermissionStatus.hpp +88 -0
- package/nitrogen/generated/shared/c++/SpeedAlertType.hpp +80 -0
- package/nitrogen/generated/shared/c++/SpeedConfig.hpp +91 -0
- package/nitrogen/generated/shared/c++/TripStats.hpp +99 -0
- package/package.json +2 -2
- package/src/NitroLocationTracking.nitro.ts +71 -0
- package/src/index.tsx +10 -0
package/README.md
CHANGED
|
@@ -1,28 +1,698 @@
|
|
|
1
1
|
# react-native-nitro-location-tracking
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
A high-performance React Native location tracking library built with [Nitro Modules](https://nitro.margelo.com/). Designed for ride-hailing, delivery, and fleet tracking apps with background location, WebSocket connectivity, foreground service notifications, and smooth map marker animations.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Background location tracking** with foreground service (Android) and background modes (iOS)
|
|
8
|
+
- **WebSocket connection manager** with auto-reconnect and batch sync
|
|
9
|
+
- **Fake GPS detection** — detect mock locations and optionally reject them
|
|
10
|
+
- **Geofencing** — monitor enter/exit events for circular regions
|
|
11
|
+
- **Speed Monitoring** — configurable speed alerts with state-transition callbacks
|
|
12
|
+
- **Distance Calculator** — running trip stats with Haversine distance
|
|
13
|
+
- **Location Provider Status** — detect when GPS/location is turned on/off
|
|
14
|
+
- **Smooth map marker animations** via `LocationSmoother`
|
|
15
|
+
- **Bearing calculation** utilities for rotation/heading
|
|
16
|
+
- **Foreground notifications** (Android foreground service, iOS local notifications)
|
|
17
|
+
- **Permission helpers** for fine, background, and notification permissions
|
|
18
|
+
- **Built on Nitro Modules** for near-native performance via JSI
|
|
6
19
|
|
|
20
|
+
## Installation
|
|
7
21
|
|
|
8
22
|
```sh
|
|
9
23
|
npm install react-native-nitro-location-tracking react-native-nitro-modules
|
|
24
|
+
# or
|
|
25
|
+
yarn add react-native-nitro-location-tracking react-native-nitro-modules
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
> `react-native-nitro-modules` is a required peer dependency.
|
|
29
|
+
|
|
30
|
+
### iOS Setup
|
|
10
31
|
|
|
11
|
-
|
|
32
|
+
1. Install pods:
|
|
33
|
+
|
|
34
|
+
```sh
|
|
35
|
+
cd ios && pod install
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
1. Add the following keys to your `Info.plist`:
|
|
39
|
+
|
|
40
|
+
```xml
|
|
41
|
+
<key>NSLocationWhenInUseUsageDescription</key>
|
|
42
|
+
<string>We need your location to track your ride.</string>
|
|
43
|
+
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
|
|
44
|
+
<string>We need background location access to continue tracking while the app is minimized.</string>
|
|
12
45
|
```
|
|
13
46
|
|
|
47
|
+
1. Enable **Background Modes** in Xcode:
|
|
48
|
+
- Go to your target > **Signing & Capabilities** > **+ Capability** > **Background Modes**
|
|
49
|
+
- Check **Location updates**
|
|
50
|
+
|
|
51
|
+
### Android Setup
|
|
52
|
+
|
|
53
|
+
The library's `AndroidManifest.xml` automatically merges the required permissions and the foreground service declaration. No manual changes needed.
|
|
54
|
+
|
|
55
|
+
Permissions included automatically:
|
|
56
|
+
|
|
57
|
+
- `ACCESS_FINE_LOCATION`
|
|
58
|
+
- `ACCESS_COARSE_LOCATION`
|
|
59
|
+
- `ACCESS_BACKGROUND_LOCATION`
|
|
60
|
+
- `FOREGROUND_SERVICE`
|
|
61
|
+
- `FOREGROUND_SERVICE_LOCATION`
|
|
62
|
+
- `POST_NOTIFICATIONS`
|
|
63
|
+
- `INTERNET`
|
|
64
|
+
- `RECEIVE_BOOT_COMPLETED`
|
|
65
|
+
- `WAKE_LOCK`
|
|
14
66
|
|
|
15
67
|
## Usage
|
|
16
68
|
|
|
69
|
+
### Request Permissions
|
|
70
|
+
|
|
71
|
+
Call this before starting location tracking, especially on Android:
|
|
72
|
+
|
|
73
|
+
```tsx
|
|
74
|
+
import { requestLocationPermission } from 'react-native-nitro-location-tracking';
|
|
75
|
+
|
|
76
|
+
const granted = await requestLocationPermission();
|
|
77
|
+
if (!granted) {
|
|
78
|
+
console.warn('Location permission denied');
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
You can customize the permission dialog messages:
|
|
83
|
+
|
|
84
|
+
```tsx
|
|
85
|
+
const granted = await requestLocationPermission(
|
|
86
|
+
{
|
|
87
|
+
title: 'Location Access',
|
|
88
|
+
message: 'We need your location to show your position on the map.',
|
|
89
|
+
buttonPositive: 'Allow',
|
|
90
|
+
buttonNegative: 'Deny',
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
title: 'Background Location',
|
|
94
|
+
message: 'Allow background location to keep tracking while the app is minimized.',
|
|
95
|
+
buttonPositive: 'Allow',
|
|
96
|
+
buttonNegative: 'Deny',
|
|
97
|
+
}
|
|
98
|
+
);
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
> On iOS, permissions are handled via `Info.plist` and the system prompt on first access.
|
|
102
|
+
|
|
103
|
+
### Location Tracking with `useDriverLocation`
|
|
104
|
+
|
|
105
|
+
The simplest way to track location using the built-in React hook:
|
|
106
|
+
|
|
107
|
+
```tsx
|
|
108
|
+
import { useDriverLocation } from 'react-native-nitro-location-tracking';
|
|
109
|
+
import type { LocationConfig } from 'react-native-nitro-location-tracking';
|
|
110
|
+
|
|
111
|
+
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)
|
|
119
|
+
foregroundNotificationTitle: 'Tracking Active',
|
|
120
|
+
foregroundNotificationText: 'Your location is being tracked',
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
function DriverScreen() {
|
|
124
|
+
const { location, isMoving, isTracking, startTracking, stopTracking } =
|
|
125
|
+
useDriverLocation(config);
|
|
126
|
+
|
|
127
|
+
return (
|
|
128
|
+
<View>
|
|
129
|
+
<Text>Tracking: {isTracking ? 'Yes' : 'No'}</Text>
|
|
130
|
+
<Text>Moving: {isMoving ? 'Yes' : 'No'}</Text>
|
|
131
|
+
{location && (
|
|
132
|
+
<Text>
|
|
133
|
+
{location.latitude.toFixed(6)}, {location.longitude.toFixed(6)}
|
|
134
|
+
{'\n'}Speed: {location.speed} m/s | Bearing: {location.bearing}°
|
|
135
|
+
</Text>
|
|
136
|
+
)}
|
|
137
|
+
<Button title="Start" onPress={startTracking} />
|
|
138
|
+
<Button title="Stop" onPress={stopTracking} />
|
|
139
|
+
</View>
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### WebSocket Connection with `useRideConnection`
|
|
145
|
+
|
|
146
|
+
Manage a WebSocket connection for real-time location sync:
|
|
147
|
+
|
|
148
|
+
```tsx
|
|
149
|
+
import { useRideConnection } from 'react-native-nitro-location-tracking';
|
|
150
|
+
import type { ConnectionConfig } from 'react-native-nitro-location-tracking';
|
|
151
|
+
|
|
152
|
+
const connectionConfig: ConnectionConfig = {
|
|
153
|
+
wsUrl: 'wss://api.example.com/ws/driver',
|
|
154
|
+
restUrl: 'https://api.example.com/api',
|
|
155
|
+
authToken: 'your-auth-token',
|
|
156
|
+
reconnectIntervalMs: 5000,
|
|
157
|
+
maxReconnectAttempts: 10,
|
|
158
|
+
batchSize: 5, // locations per batch upload
|
|
159
|
+
syncIntervalMs: 10000, // flush queue every 10s
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
function RideScreen() {
|
|
163
|
+
const { connectionState, lastMessage, connect, disconnect, send } =
|
|
164
|
+
useRideConnection(connectionConfig);
|
|
165
|
+
|
|
166
|
+
return (
|
|
167
|
+
<View>
|
|
168
|
+
<Text>Connection: {connectionState}</Text>
|
|
169
|
+
<Text>Last message: {lastMessage}</Text>
|
|
170
|
+
<Button title="Connect" onPress={connect} />
|
|
171
|
+
<Button title="Disconnect" onPress={disconnect} />
|
|
172
|
+
<Button title="Send Ping" onPress={() => send('ping')} />
|
|
173
|
+
</View>
|
|
174
|
+
);
|
|
175
|
+
}
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
### Direct Module Access
|
|
179
|
+
|
|
180
|
+
For advanced use cases, access the native module directly:
|
|
181
|
+
|
|
182
|
+
```tsx
|
|
183
|
+
import NitroLocationModule from 'react-native-nitro-location-tracking';
|
|
184
|
+
|
|
185
|
+
// Configure and start tracking
|
|
186
|
+
NitroLocationModule.configure(config);
|
|
187
|
+
NitroLocationModule.onLocation((location) => {
|
|
188
|
+
console.log('New location:', location);
|
|
189
|
+
});
|
|
190
|
+
NitroLocationModule.onMotionChange((isMoving) => {
|
|
191
|
+
console.log('Motion changed:', isMoving);
|
|
192
|
+
});
|
|
193
|
+
NitroLocationModule.startTracking();
|
|
194
|
+
|
|
195
|
+
// Get current location (one-shot)
|
|
196
|
+
const current = await NitroLocationModule.getCurrentLocation();
|
|
197
|
+
|
|
198
|
+
// Check tracking state
|
|
199
|
+
const tracking = NitroLocationModule.isTracking();
|
|
200
|
+
|
|
201
|
+
// Stop tracking
|
|
202
|
+
NitroLocationModule.stopTracking();
|
|
203
|
+
|
|
204
|
+
// Force sync queued locations
|
|
205
|
+
const synced = await NitroLocationModule.forceSync();
|
|
206
|
+
|
|
207
|
+
// Notifications
|
|
208
|
+
NitroLocationModule.showLocalNotification('Ride Started', 'Heading to pickup');
|
|
209
|
+
NitroLocationModule.updateForegroundNotification('En Route', '2.5 km away');
|
|
210
|
+
|
|
211
|
+
// Cleanup
|
|
212
|
+
NitroLocationModule.destroy();
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
### Fake GPS Detection
|
|
216
|
+
|
|
217
|
+
Detect mock/fake GPS locations and optionally reject them:
|
|
218
|
+
|
|
219
|
+
```tsx
|
|
220
|
+
import NitroLocationModule from 'react-native-nitro-location-tracking';
|
|
221
|
+
|
|
222
|
+
// Check if device-level mock location is enabled
|
|
223
|
+
const fakeGpsOn = NitroLocationModule.isFakeGpsEnabled();
|
|
224
|
+
if (fakeGpsOn) {
|
|
225
|
+
console.warn('Mock location provider is active!');
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// Auto-reject mock locations (they won't fire onLocation callbacks)
|
|
229
|
+
NitroLocationModule.setRejectMockLocations(true);
|
|
230
|
+
|
|
231
|
+
// Each location update includes isMockLocation flag
|
|
232
|
+
NitroLocationModule.onLocation((location) => {
|
|
233
|
+
if (location.isMockLocation) {
|
|
234
|
+
console.warn('This location is from a mock provider');
|
|
235
|
+
}
|
|
236
|
+
});
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
**Platform behavior:**
|
|
240
|
+
|
|
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 |
|
|
245
|
+
|
|
246
|
+
### Smooth Map Marker Animation
|
|
247
|
+
|
|
248
|
+
Use `LocationSmoother` to animate a map marker smoothly between location updates:
|
|
249
|
+
|
|
250
|
+
```tsx
|
|
251
|
+
import { useRef, useCallback } from 'react';
|
|
252
|
+
import { Marker } from 'react-native-maps';
|
|
253
|
+
import {
|
|
254
|
+
useDriverLocation,
|
|
255
|
+
LocationSmoother,
|
|
256
|
+
} from 'react-native-nitro-location-tracking';
|
|
257
|
+
|
|
258
|
+
function MapScreen() {
|
|
259
|
+
const markerRef = useRef(null);
|
|
260
|
+
const smootherRef = useRef(new LocationSmoother(markerRef));
|
|
261
|
+
|
|
262
|
+
const { location, startTracking } = useDriverLocation(config);
|
|
263
|
+
|
|
264
|
+
// Feed each new location into the smoother
|
|
265
|
+
const onLocation = useCallback((loc) => {
|
|
266
|
+
smootherRef.current.feed(loc);
|
|
267
|
+
}, []);
|
|
268
|
+
|
|
269
|
+
return (
|
|
270
|
+
<MapView>
|
|
271
|
+
{location && (
|
|
272
|
+
<Marker
|
|
273
|
+
ref={markerRef}
|
|
274
|
+
coordinate={{
|
|
275
|
+
latitude: location.latitude,
|
|
276
|
+
longitude: location.longitude,
|
|
277
|
+
}}
|
|
278
|
+
/>
|
|
279
|
+
)}
|
|
280
|
+
</MapView>
|
|
281
|
+
);
|
|
282
|
+
}
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
### Bearing Utilities
|
|
286
|
+
|
|
287
|
+
Calculate bearing between two coordinates and handle rotation smoothing:
|
|
288
|
+
|
|
289
|
+
```tsx
|
|
290
|
+
import { calculateBearing, shortestRotation } from 'react-native-nitro-location-tracking';
|
|
291
|
+
|
|
292
|
+
// Calculate bearing from point A to point B (in degrees, 0-360)
|
|
293
|
+
const bearing = calculateBearing(
|
|
294
|
+
{ latitude: 41.311, longitude: 69.279 },
|
|
295
|
+
{ latitude: 41.315, longitude: 69.285 }
|
|
296
|
+
);
|
|
297
|
+
|
|
298
|
+
// Smooth rotation to avoid spinning the long way around
|
|
299
|
+
const currentRotation = 350;
|
|
300
|
+
const targetRotation = 10;
|
|
301
|
+
const smoothed = shortestRotation(currentRotation, targetRotation); // 370 (not -350)
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
### Geofencing
|
|
305
|
+
|
|
306
|
+
Monitor enter/exit events for circular regions:
|
|
307
|
+
|
|
308
|
+
```tsx
|
|
309
|
+
import NitroLocationModule from 'react-native-nitro-location-tracking';
|
|
310
|
+
import type { GeofenceRegion } from 'react-native-nitro-location-tracking';
|
|
311
|
+
|
|
312
|
+
// Listen for geofence events
|
|
313
|
+
NitroLocationModule.onGeofenceEvent((event, regionId) => {
|
|
314
|
+
console.log(`Geofence ${event} for region: ${regionId}`);
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
// Add a geofence around a pickup point
|
|
318
|
+
NitroLocationModule.addGeofence({
|
|
319
|
+
id: 'pickup-zone',
|
|
320
|
+
latitude: 41.311,
|
|
321
|
+
longitude: 69.279,
|
|
322
|
+
radius: 100, // meters
|
|
323
|
+
notifyOnEntry: true,
|
|
324
|
+
notifyOnExit: true,
|
|
325
|
+
});
|
|
326
|
+
|
|
327
|
+
// Remove a specific geofence
|
|
328
|
+
NitroLocationModule.removeGeofence('pickup-zone');
|
|
329
|
+
|
|
330
|
+
// Remove all geofences
|
|
331
|
+
NitroLocationModule.removeAllGeofences();
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
> **Note:** iOS limits geofence regions to 20 per app. Android supports up to 100.
|
|
335
|
+
|
|
336
|
+
### Speed Monitoring
|
|
337
|
+
|
|
338
|
+
Get alerts when speed crosses configurable thresholds:
|
|
339
|
+
|
|
340
|
+
```tsx
|
|
341
|
+
import NitroLocationModule from 'react-native-nitro-location-tracking';
|
|
342
|
+
|
|
343
|
+
// Configure speed thresholds
|
|
344
|
+
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
|
|
348
|
+
});
|
|
349
|
+
|
|
350
|
+
// Listen for speed state transitions
|
|
351
|
+
NitroLocationModule.onSpeedAlert((alert, speedKmh) => {
|
|
352
|
+
if (alert === 'exceeded') {
|
|
353
|
+
console.warn(`Speed limit exceeded: ${speedKmh.toFixed(1)} km/h`);
|
|
354
|
+
} else if (alert === 'below_minimum') {
|
|
355
|
+
console.log('Driver appears idle');
|
|
356
|
+
} else {
|
|
357
|
+
console.log('Speed normalized');
|
|
358
|
+
}
|
|
359
|
+
});
|
|
360
|
+
|
|
361
|
+
// Get current speed anytime
|
|
362
|
+
const speed = NitroLocationModule.getCurrentSpeed(); // km/h
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
### Distance Calculator
|
|
366
|
+
|
|
367
|
+
Track running trip statistics:
|
|
368
|
+
|
|
369
|
+
```tsx
|
|
370
|
+
import NitroLocationModule from 'react-native-nitro-location-tracking';
|
|
17
371
|
|
|
18
|
-
|
|
19
|
-
|
|
372
|
+
// Start recording a trip
|
|
373
|
+
NitroLocationModule.startTripCalculation();
|
|
20
374
|
|
|
21
|
-
//
|
|
375
|
+
// Check stats during the trip
|
|
376
|
+
const stats = NitroLocationModule.getTripStats();
|
|
377
|
+
console.log(`Distance: ${(stats.distanceMeters / 1000).toFixed(2)} km`);
|
|
378
|
+
console.log(`Duration: ${(stats.durationMs / 60000).toFixed(1)} min`);
|
|
379
|
+
console.log(`Avg speed: ${stats.averageSpeedKmh.toFixed(1)} km/h`);
|
|
380
|
+
console.log(`Max speed: ${stats.maxSpeedKmh.toFixed(1)} km/h`);
|
|
381
|
+
console.log(`Points: ${stats.pointCount}`);
|
|
22
382
|
|
|
23
|
-
|
|
383
|
+
// Stop and get final stats
|
|
384
|
+
const finalStats = NitroLocationModule.stopTripCalculation();
|
|
385
|
+
|
|
386
|
+
// Reset for a new trip
|
|
387
|
+
NitroLocationModule.resetTripCalculation();
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
### Location Provider Status
|
|
391
|
+
|
|
392
|
+
Detect when GPS/location services are turned on or off:
|
|
393
|
+
|
|
394
|
+
```tsx
|
|
395
|
+
import NitroLocationModule from 'react-native-nitro-location-tracking';
|
|
396
|
+
|
|
397
|
+
// Check current status
|
|
398
|
+
const enabled = NitroLocationModule.isLocationServicesEnabled();
|
|
399
|
+
|
|
400
|
+
// Listen for changes
|
|
401
|
+
NitroLocationModule.onProviderStatusChange((gps, network) => {
|
|
402
|
+
console.log(`GPS: ${gps}, Network: ${network}`);
|
|
403
|
+
if (gps === 'disabled') {
|
|
404
|
+
console.warn('Please enable location services!');
|
|
405
|
+
}
|
|
406
|
+
});
|
|
407
|
+
```
|
|
408
|
+
|
|
409
|
+
### Permission Status
|
|
410
|
+
|
|
411
|
+
Check the current location permission status without prompting the user:
|
|
412
|
+
|
|
413
|
+
```tsx
|
|
414
|
+
import NitroLocationModule from 'react-native-nitro-location-tracking';
|
|
415
|
+
|
|
416
|
+
const status = NitroLocationModule.getLocationPermissionStatus();
|
|
417
|
+
|
|
418
|
+
switch (status) {
|
|
419
|
+
case 'always':
|
|
420
|
+
console.log('Background location granted');
|
|
421
|
+
break;
|
|
422
|
+
case 'whenInUse':
|
|
423
|
+
console.log('Foreground only — background tracking may not work');
|
|
424
|
+
break;
|
|
425
|
+
case 'denied':
|
|
426
|
+
console.warn('Location permission denied');
|
|
427
|
+
break;
|
|
428
|
+
case 'restricted':
|
|
429
|
+
console.warn('Location restricted by parental controls or MDM');
|
|
430
|
+
break;
|
|
431
|
+
case 'notDetermined':
|
|
432
|
+
console.log('Permission not yet requested');
|
|
433
|
+
break;
|
|
434
|
+
}
|
|
435
|
+
```
|
|
436
|
+
|
|
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 |
|
|
444
|
+
|
|
445
|
+
## API Reference
|
|
446
|
+
|
|
447
|
+
### Types
|
|
448
|
+
|
|
449
|
+
#### `LocationData`
|
|
450
|
+
|
|
451
|
+
```ts
|
|
452
|
+
interface LocationData {
|
|
453
|
+
latitude: number;
|
|
454
|
+
longitude: number;
|
|
455
|
+
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
|
|
461
|
+
}
|
|
462
|
+
```
|
|
463
|
+
|
|
464
|
+
#### `LocationConfig`
|
|
465
|
+
|
|
466
|
+
```ts
|
|
467
|
+
interface LocationConfig {
|
|
468
|
+
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)
|
|
475
|
+
foregroundNotificationTitle: string;
|
|
476
|
+
foregroundNotificationText: string;
|
|
477
|
+
}
|
|
478
|
+
```
|
|
479
|
+
|
|
480
|
+
#### `ConnectionConfig`
|
|
481
|
+
|
|
482
|
+
```ts
|
|
483
|
+
interface ConnectionConfig {
|
|
484
|
+
wsUrl: string;
|
|
485
|
+
restUrl: string;
|
|
486
|
+
authToken: string;
|
|
487
|
+
reconnectIntervalMs: number;
|
|
488
|
+
maxReconnectAttempts: number;
|
|
489
|
+
batchSize: number; // locations per batch upload
|
|
490
|
+
syncIntervalMs: number; // how often to flush queue
|
|
491
|
+
}
|
|
492
|
+
```
|
|
493
|
+
|
|
494
|
+
#### `GeofenceRegion`
|
|
495
|
+
|
|
496
|
+
```ts
|
|
497
|
+
interface GeofenceRegion {
|
|
498
|
+
id: string;
|
|
499
|
+
latitude: number;
|
|
500
|
+
longitude: number;
|
|
501
|
+
radius: number; // meters
|
|
502
|
+
notifyOnEntry: boolean;
|
|
503
|
+
notifyOnExit: boolean;
|
|
504
|
+
}
|
|
505
|
+
```
|
|
506
|
+
|
|
507
|
+
#### `SpeedConfig`
|
|
508
|
+
|
|
509
|
+
```ts
|
|
510
|
+
interface SpeedConfig {
|
|
511
|
+
maxSpeedKmh: number; // speed limit in km/h
|
|
512
|
+
minSpeedKmh: number; // minimum speed threshold
|
|
513
|
+
checkIntervalMs: number; // how often to evaluate
|
|
514
|
+
}
|
|
515
|
+
```
|
|
516
|
+
|
|
517
|
+
#### `TripStats`
|
|
518
|
+
|
|
519
|
+
```ts
|
|
520
|
+
interface TripStats {
|
|
521
|
+
distanceMeters: number;
|
|
522
|
+
durationMs: number;
|
|
523
|
+
averageSpeedKmh: number;
|
|
524
|
+
maxSpeedKmh: number;
|
|
525
|
+
pointCount: number;
|
|
526
|
+
}
|
|
527
|
+
```
|
|
528
|
+
|
|
529
|
+
#### `PermissionStatus`
|
|
530
|
+
|
|
531
|
+
```ts
|
|
532
|
+
type PermissionStatus =
|
|
533
|
+
| 'notDetermined'
|
|
534
|
+
| 'denied'
|
|
535
|
+
| 'restricted'
|
|
536
|
+
| 'whenInUse'
|
|
537
|
+
| 'always';
|
|
538
|
+
```
|
|
539
|
+
|
|
540
|
+
### Hooks
|
|
541
|
+
|
|
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 |
|
|
546
|
+
|
|
547
|
+
### Native Module Methods
|
|
548
|
+
|
|
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 |
|
|
585
|
+
|
|
586
|
+
### Utility Exports
|
|
587
|
+
|
|
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) |
|
|
594
|
+
|
|
595
|
+
## Publishing to npm
|
|
596
|
+
|
|
597
|
+
### Prerequisites
|
|
598
|
+
|
|
599
|
+
1. Create an npm account at [npmjs.com](https://www.npmjs.com/signup)
|
|
600
|
+
2. Log in from terminal:
|
|
601
|
+
|
|
602
|
+
```sh
|
|
603
|
+
npm login
|
|
604
|
+
```
|
|
605
|
+
|
|
606
|
+
### First-time Publish
|
|
607
|
+
|
|
608
|
+
1. Make sure the build is up to date:
|
|
609
|
+
|
|
610
|
+
```sh
|
|
611
|
+
yarn prepare
|
|
612
|
+
```
|
|
613
|
+
|
|
614
|
+
1. Do a dry run to verify what will be published:
|
|
615
|
+
|
|
616
|
+
```sh
|
|
617
|
+
npm pack --dry-run
|
|
618
|
+
```
|
|
619
|
+
|
|
620
|
+
1. Publish:
|
|
621
|
+
|
|
622
|
+
```sh
|
|
623
|
+
npm publish
|
|
624
|
+
```
|
|
625
|
+
|
|
626
|
+
> The package is configured with `"publishConfig": { "registry": "https://registry.npmjs.org/" }` so it will publish to the public npm registry.
|
|
627
|
+
|
|
628
|
+
### Release with Versioning (Recommended)
|
|
629
|
+
|
|
630
|
+
This project uses [release-it](https://github.com/release-it/release-it) with conventional changelog. To create a proper release:
|
|
631
|
+
|
|
632
|
+
```sh
|
|
633
|
+
yarn release
|
|
24
634
|
```
|
|
25
635
|
|
|
636
|
+
This will:
|
|
637
|
+
|
|
638
|
+
- Bump the version based on your commits
|
|
639
|
+
- Generate a changelog
|
|
640
|
+
- Create a git commit and tag
|
|
641
|
+
- Publish to npm
|
|
642
|
+
- Create a GitHub release
|
|
643
|
+
|
|
644
|
+
For a specific version bump:
|
|
645
|
+
|
|
646
|
+
```sh
|
|
647
|
+
# Patch release (0.1.5 -> 0.1.6)
|
|
648
|
+
npx release-it patch
|
|
649
|
+
|
|
650
|
+
# Minor release (0.1.5 -> 0.2.0)
|
|
651
|
+
npx release-it minor
|
|
652
|
+
|
|
653
|
+
# Major release (0.1.5 -> 1.0.0)
|
|
654
|
+
npx release-it major
|
|
655
|
+
```
|
|
656
|
+
|
|
657
|
+
### Manual Version Bump + Publish
|
|
658
|
+
|
|
659
|
+
```sh
|
|
660
|
+
# 1. Bump version
|
|
661
|
+
npm version patch # or minor / major
|
|
662
|
+
|
|
663
|
+
# 2. Build
|
|
664
|
+
yarn prepare
|
|
665
|
+
|
|
666
|
+
# 3. Publish
|
|
667
|
+
npm publish
|
|
668
|
+
|
|
669
|
+
# 4. Push tags
|
|
670
|
+
git push --follow-tags
|
|
671
|
+
```
|
|
672
|
+
|
|
673
|
+
### What Gets Published
|
|
674
|
+
|
|
675
|
+
The `files` field in `package.json` controls what is included in the npm package:
|
|
676
|
+
|
|
677
|
+
- `src/` - TypeScript source
|
|
678
|
+
- `lib/` - Compiled JS + type declarations
|
|
679
|
+
- `android/` - Android native code (excluding build artifacts)
|
|
680
|
+
- `ios/` - iOS native code (excluding build folder)
|
|
681
|
+
- `cpp/` - C++ shared code
|
|
682
|
+
- `nitrogen/` - Nitro generated code
|
|
683
|
+
- `nitro.json` - Nitro module configuration
|
|
684
|
+
- `*.podspec` - CocoaPods spec
|
|
685
|
+
- `react-native.config.js` - React Native CLI config
|
|
686
|
+
|
|
687
|
+
### Unpublishing / Deprecating
|
|
688
|
+
|
|
689
|
+
```sh
|
|
690
|
+
# Deprecate a version (users see a warning on install)
|
|
691
|
+
npm deprecate react-native-nitro-location-tracking@"< 0.2.0" "please upgrade to 0.2.0+"
|
|
692
|
+
|
|
693
|
+
# Unpublish a specific version (within 72 hours only)
|
|
694
|
+
npm unpublish react-native-nitro-location-tracking@0.1.0
|
|
695
|
+
```
|
|
26
696
|
|
|
27
697
|
## Contributing
|
|
28
698
|
|