react-native-nitro-geolocation 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +251 -531
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,598 +1,318 @@
|
|
|
1
1
|
# react-native-nitro-geolocation
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
#### `@react-native-community/geolocation` (Old Bridge)
|
|
10
|
-
```
|
|
11
|
-
┌─────────────┐
|
|
12
|
-
│ JS │
|
|
13
|
-
└──────┬──────┘
|
|
14
|
-
│ serialize JSON
|
|
15
|
-
▼
|
|
16
|
-
┌─────────────┐
|
|
17
|
-
│ Bridge │ ← Async message queue
|
|
18
|
-
└──────┬──────┘
|
|
19
|
-
│ deserialize JSON
|
|
20
|
-
▼
|
|
21
|
-
┌─────────────┐
|
|
22
|
-
│ Java/ObjC │
|
|
23
|
-
└─────────────┘
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
**Characteristics:**
|
|
27
|
-
- **Asynchronous**: All calls go through message queue
|
|
28
|
-
- **Serialization overhead**: Every data structure must be serialized/deserialized
|
|
29
|
-
- **Event emitter pattern**: Uses `DeviceEventEmitter` for location updates
|
|
30
|
-
- **Indirect callbacks**: Events broadcast to all JS listeners
|
|
31
|
-
|
|
32
|
-
#### `react-native-nitro-geolocation` (Nitro/JSI)
|
|
33
|
-
```
|
|
34
|
-
┌─────────────┐
|
|
35
|
-
│ JS │
|
|
36
|
-
└──────┬──────┘
|
|
37
|
-
│ direct memory access
|
|
38
|
-
▼
|
|
39
|
-
┌─────────────┐
|
|
40
|
-
│ C++ (JSI) │ ← Type-safe bindings
|
|
41
|
-
└──────┬──────┘
|
|
42
|
-
│ direct function call
|
|
43
|
-
▼
|
|
44
|
-
┌─────────────┐
|
|
45
|
-
│Kotlin/Swift │
|
|
46
|
-
└─────────────┘
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
**Characteristics:**
|
|
50
|
-
- **Synchronous capable**: Direct C++ function calls (getCurrentPosition still async due to GPS)
|
|
51
|
-
- **Zero serialization**: Shared memory between JS and native
|
|
52
|
-
- **Direct callbacks**: Native directly invokes JS functions via JSI
|
|
53
|
-
- **Type-safe**: Compile-time type checking in C++
|
|
3
|
+
[](https://www.npmjs.com/package/react-native-nitro-geolocation)
|
|
4
|
+
|
|
5
|
+
[`@react-native-community/geolocation`](https://github.com/michalchudziak/react-native-geolocation)
|
|
6
|
+
for the **React Native New Architecture** — with 100% API compatibility.
|
|
7
|
+
|
|
8
|
+

|
|
93
16
|
|
|
94
17
|
---
|
|
95
18
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
- **Bridge**: Callbacks are serialized as IDs, invoked through message queue
|
|
138
|
-
- **Nitro**: Callbacks are actual C++ function pointers to JS functions
|
|
19
|
+
## 🧭 Introduction
|
|
20
|
+
|
|
21
|
+
The `@react-native-community/geolocation` package has long been the standard way to access device location in React Native apps.
|
|
22
|
+
|
|
23
|
+
With React Native moving toward **Nitro Modules**, **Fabric**, and **JSI**,
|
|
24
|
+
this project — **React Native Nitro Geolocation** — brings the same familiar API to the new architecture.
|
|
25
|
+
|
|
26
|
+
It provides the **same API surface** with:
|
|
27
|
+
|
|
28
|
+
- 🚀 Faster performance via direct **JSI bindings**
|
|
29
|
+
- 📱 Improved native consistency (Android + iOS)
|
|
30
|
+
- 🔁 Seamless migration from `@react-native-community/geolocation`
|
|
31
|
+
- 🧩 TypeScript-first developer experience
|
|
32
|
+
- 🔄 100% API compatibility (drop-in replacement)
|
|
33
|
+
|
|
34
|
+
Whether upgrading an existing app or building a new one,
|
|
35
|
+
**React Native Nitro Geolocation** keeps the simplicity you know — with modern internals.
|
|
36
|
+
|
|
37
|
+
## 🏗 Architecture Comparison
|
|
38
|
+
|
|
39
|
+
### 🧩 Origin: Event-based Architecture (`@react-native-community/geolocation`)
|
|
40
|
+
|
|
41
|
+
~~~
|
|
42
|
+
JavaScript
|
|
43
|
+
↓ EventEmitter.addListener('geolocationDidChange', callback)
|
|
44
|
+
↓ (Callback stored in JS)
|
|
45
|
+
React Native Bridge (JSON serialization)
|
|
46
|
+
↓
|
|
47
|
+
Native Layer (Android/iOS)
|
|
48
|
+
↓ LocationListener receives updates
|
|
49
|
+
↓ emit('geolocationDidChange', data)
|
|
50
|
+
↓
|
|
51
|
+
EventEmitter dispatches to all listeners
|
|
52
|
+
↓
|
|
53
|
+
User callback executed
|
|
54
|
+
~~~
|
|
55
|
+
|
|
56
|
+
**Key traits:**
|
|
57
|
+
- Callbacks stored only in JS
|
|
58
|
+
- Bridge serialization on every update
|
|
59
|
+
- One shared event stream
|
|
139
60
|
|
|
140
61
|
---
|
|
141
62
|
|
|
142
|
-
###
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
**Data flow:**
|
|
163
|
-
```
|
|
164
|
-
Android LocationManager
|
|
165
|
-
→ LocationListener.onLocationChanged(Location)
|
|
166
|
-
→ locationToMap(Location) // Create WritableMap
|
|
167
|
-
→ success.invoke(WritableMap) // Serialize to JSON
|
|
168
|
-
→ Bridge message queue
|
|
169
|
-
→ JS deserialize JSON
|
|
170
|
-
→ User callback
|
|
171
|
-
```
|
|
172
|
-
|
|
173
|
-
**Overhead**: ~1-3ms per location update
|
|
174
|
-
|
|
175
|
-
#### Nitro Architecture
|
|
176
|
-
```kotlin
|
|
177
|
-
// GetCurrentPosition.kt
|
|
178
|
-
fun execute(
|
|
179
|
-
success: (position: GeolocationResponse) -> Unit,
|
|
180
|
-
error: ((error: GeolocationError) -> Unit)?,
|
|
181
|
-
options: GeolocationOptions?
|
|
182
|
-
) {
|
|
183
|
-
val listener = object : LocationListener {
|
|
184
|
-
override fun onLocationChanged(location: Location) {
|
|
185
|
-
success(locationToPosition(location)) // Direct JSI call
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
locationManager.requestLocationUpdates(provider, 100, 1f, listener, Looper.getMainLooper())
|
|
189
|
-
}
|
|
190
|
-
```
|
|
191
|
-
|
|
192
|
-
**Data flow:**
|
|
193
|
-
```
|
|
194
|
-
Android LocationManager
|
|
195
|
-
→ LocationListener.onLocationChanged(Location)
|
|
196
|
-
→ locationToPosition(Location) // Create Kotlin data class
|
|
197
|
-
→ success(GeolocationResponse) // Direct JSI invocation
|
|
198
|
-
→ User callback (zero serialization)
|
|
199
|
-
```
|
|
200
|
-
|
|
201
|
-
**Overhead**: ~0.01-0.1ms per location update
|
|
202
|
-
|
|
203
|
-
**Additional Improvements:**
|
|
204
|
-
1. **Better location algorithm**: Implements `isBetterLocation()` from Android docs
|
|
205
|
-
2. **Modern API support**: Uses `getCurrentLocation()` API on Android 11+
|
|
206
|
-
3. **Timeout with fallback**: Returns last known location on timeout (configurable)
|
|
63
|
+
### ⚡ Modern: Direct Callback Architecture (`react-native-nitro-geolocation`)
|
|
64
|
+
|
|
65
|
+
~~~
|
|
66
|
+
JavaScript
|
|
67
|
+
↓ Geolocation.watchPosition(success, error)
|
|
68
|
+
↓ (Callbacks passed directly to native via JSI)
|
|
69
|
+
JSI Layer (No Bridge!)
|
|
70
|
+
↓
|
|
71
|
+
Native Layer (Kotlin/Swift)
|
|
72
|
+
↓ callback.success(position) → JSI direct call
|
|
73
|
+
↓
|
|
74
|
+
User callback executed immediately
|
|
75
|
+
~~~
|
|
76
|
+
|
|
77
|
+
**Key traits:**
|
|
78
|
+
- Callbacks passed as native JSI references
|
|
79
|
+
- No Bridge serialization
|
|
80
|
+
- Independent callback per watcher
|
|
81
|
+
- Native → JS communication in real time
|
|
207
82
|
|
|
208
83
|
---
|
|
209
84
|
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
locationManager.requestLocationUpdates(provider, 1000, distanceFilter, mLocationListener);
|
|
228
|
-
}
|
|
229
|
-
```
|
|
230
|
-
|
|
231
|
-
**Architecture:**
|
|
232
|
-
```
|
|
233
|
-
┌──────────────────────────────┐
|
|
234
|
-
│ Android LocationManager │
|
|
235
|
-
└──────────────┬───────────────┘
|
|
236
|
-
│ Single LocationListener
|
|
237
|
-
▼
|
|
238
|
-
┌──────────────────────────────┐
|
|
239
|
-
│ mLocationListener │
|
|
240
|
-
└──────────────┬───────────────┘
|
|
241
|
-
│ emit("geolocationDidChange", location)
|
|
242
|
-
▼
|
|
243
|
-
┌──────────────────────────────┐
|
|
244
|
-
│ DeviceEventEmitter │ ← Serialize location to JSON
|
|
245
|
-
└──────────────┬───────────────┘
|
|
246
|
-
│ Bridge
|
|
247
|
-
▼
|
|
248
|
-
┌──────────────────────────────┐
|
|
249
|
-
│ JS EventEmitter │
|
|
250
|
-
└──────────────┬───────────────┘
|
|
251
|
-
│ Broadcast to ALL listeners
|
|
252
|
-
├──────┬──────┬──────┐
|
|
253
|
-
▼ ▼ ▼ ▼
|
|
254
|
-
watch1 watch2 watch3 watch4 (all receive same event)
|
|
255
|
-
```
|
|
256
|
-
|
|
257
|
-
**Problems:**
|
|
258
|
-
1. **Single global listener**: Cannot have different options per watch
|
|
259
|
-
2. **Broadcast overhead**: All watches receive updates even if they have different filters
|
|
260
|
-
3. **JS-side filtering**: Each watch must filter events in JS
|
|
261
|
-
4. **Memory**: Event emitter maintains listener registry in JS
|
|
262
|
-
|
|
263
|
-
**Data flow per update:**
|
|
264
|
-
```
|
|
265
|
-
Location update (native)
|
|
266
|
-
→ serialize to JSON (1-2ms)
|
|
267
|
-
→ emit to bridge queue
|
|
268
|
-
→ deserialize in JS (1-2ms)
|
|
269
|
-
→ broadcast to N listeners (0.1ms × N)
|
|
270
|
-
→ each listener filters/processes
|
|
271
|
-
Total: ~2-5ms + (0.1ms × N listeners)
|
|
272
|
-
```
|
|
273
|
-
|
|
274
|
-
#### Nitro Architecture
|
|
275
|
-
```kotlin
|
|
276
|
-
// WatchPosition.kt
|
|
277
|
-
class WatchPosition(private val reactContext: ReactApplicationContext) {
|
|
278
|
-
// Multiple watches, each with its own callback and options
|
|
279
|
-
private val watchCallbacks = ConcurrentHashMap<Int, WatchCallback>()
|
|
280
|
-
private val watchIdGenerator = AtomicInteger(0)
|
|
281
|
-
|
|
282
|
-
data class WatchCallback(
|
|
283
|
-
val success: (GeolocationResponse) -> Unit,
|
|
284
|
-
val error: ((GeolocationError) -> Unit)?,
|
|
285
|
-
val options: GeolocationOptions?
|
|
286
|
-
)
|
|
287
|
-
|
|
288
|
-
fun watch(success: ..., error: ..., options: ...): Int {
|
|
289
|
-
val watchId = watchIdGenerator.incrementAndGet()
|
|
290
|
-
watchCallbacks[watchId] = WatchCallback(success, error, options)
|
|
291
|
-
|
|
292
|
-
// Start location updates only when first watch is added
|
|
293
|
-
if (watchCallbacks.size == 1) {
|
|
294
|
-
startObserving(options)
|
|
295
|
-
}
|
|
296
|
-
return watchId
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
private val locationListener = object : LocationListener {
|
|
300
|
-
override fun onLocationChanged(location: Location) {
|
|
301
|
-
val position = locationToPosition(location)
|
|
302
|
-
// Direct callback to each watch
|
|
303
|
-
watchCallbacks.values.forEach { callback ->
|
|
304
|
-
callback.success(position)
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
|
-
}
|
|
308
|
-
}
|
|
309
|
-
```
|
|
310
|
-
|
|
311
|
-
**Architecture:**
|
|
312
|
-
```
|
|
313
|
-
┌──────────────────────────────┐
|
|
314
|
-
│ Android LocationManager │
|
|
315
|
-
└──────────────┬───────────────┘
|
|
316
|
-
│ Single LocationListener (lazy start)
|
|
317
|
-
▼
|
|
318
|
-
┌──────────────────────────────┐
|
|
319
|
-
│ locationListener │
|
|
320
|
-
└──────────────┬───────────────┘
|
|
321
|
-
│ Direct loop over watchCallbacks
|
|
322
|
-
├──────┬──────┬──────┐
|
|
323
|
-
▼ ▼ ▼ ▼
|
|
324
|
-
watch1 watch2 watch3 watch4
|
|
325
|
-
(direct JSI invocation to each callback)
|
|
326
|
-
```
|
|
327
|
-
|
|
328
|
-
**Advantages:**
|
|
329
|
-
1. **Native watch management**: watchId and callbacks stored in native `ConcurrentHashMap`
|
|
330
|
-
2. **Direct callbacks**: Each watch callback invoked directly via JSI (no event emitter)
|
|
331
|
-
3. **Thread-safe**: `ConcurrentHashMap` + `AtomicInteger` for concurrent access
|
|
332
|
-
4. **Lazy lifecycle**: Start location updates on first watch, stop on last clearWatch
|
|
333
|
-
5. **Per-watch options**: Can support different options per watch (future enhancement)
|
|
334
|
-
|
|
335
|
-
**Data flow per update:**
|
|
336
|
-
```
|
|
337
|
-
Location update (native)
|
|
338
|
-
→ locationToPosition() (create Kotlin object, ~0.01ms)
|
|
339
|
-
→ forEach watch callback
|
|
340
|
-
→ Direct JSI call (0.01ms per watch)
|
|
341
|
-
Total: ~0.01ms + (0.01ms × N watches)
|
|
342
|
-
```
|
|
343
|
-
|
|
344
|
-
**Performance Comparison:**
|
|
345
|
-
|
|
346
|
-
| Scenario | Bridge | Nitro | Speedup |
|
|
347
|
-
|----------|--------|-------|---------|
|
|
348
|
-
| 1 watch, 1 update/sec | ~3ms/update | ~0.02ms/update | **150x** |
|
|
349
|
-
| 4 watches, 1 update/sec | ~5ms/update | ~0.05ms/update | **100x** |
|
|
350
|
-
| 1 watch, 10 updates/sec | ~30ms/sec | ~0.2ms/sec | **150x** |
|
|
351
|
-
| 4 watches, 10 updates/sec | ~50ms/sec | ~0.5ms/sec | **100x** |
|
|
85
|
+
## ⚡ Quick Start
|
|
86
|
+
|
|
87
|
+
### 1. Installation
|
|
88
|
+
|
|
89
|
+
~~~bash
|
|
90
|
+
# Install Nitro core and Geolocation module
|
|
91
|
+
yarn add react-native-nitro-modules react-native-nitro-geolocation
|
|
92
|
+
|
|
93
|
+
# or using npm
|
|
94
|
+
npm install react-native-nitro-modules react-native-nitro-geolocation
|
|
95
|
+
~~~
|
|
96
|
+
|
|
97
|
+
After installation, rebuild your native app:
|
|
98
|
+
|
|
99
|
+
~~~bash
|
|
100
|
+
cd ios && pod install
|
|
101
|
+
~~~
|
|
352
102
|
|
|
353
103
|
---
|
|
354
104
|
|
|
355
|
-
###
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
const subscription = DeviceEventEmitter.addListener('geolocationDidChange', success);
|
|
366
|
-
subscriptions.set(watchID, subscription);
|
|
367
|
-
return watchID;
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
function clearWatch(watchID) {
|
|
371
|
-
const subscription = subscriptions.get(watchID);
|
|
372
|
-
subscription?.remove(); // Removes JS listener only
|
|
373
|
-
subscriptions.delete(watchID);
|
|
374
|
-
}
|
|
375
|
-
```
|
|
376
|
-
|
|
377
|
-
**Architecture:**
|
|
378
|
-
- watchId managed in JS
|
|
379
|
-
- No native call to `clearWatch()`
|
|
380
|
-
- Native listener keeps running until `stopObserving()` called
|
|
381
|
-
|
|
382
|
-
#### Nitro Architecture
|
|
383
|
-
```kotlin
|
|
384
|
-
// WatchPosition.kt
|
|
385
|
-
fun clearWatch(watchId: Int) {
|
|
386
|
-
watchCallbacks.remove(watchId)
|
|
387
|
-
|
|
388
|
-
// Automatically stop observing if no more watches
|
|
389
|
-
if (watchCallbacks.isEmpty()) {
|
|
390
|
-
stopObserving()
|
|
391
|
-
}
|
|
392
|
-
}
|
|
393
|
-
```
|
|
394
|
-
|
|
395
|
-
**Architecture:**
|
|
396
|
-
- watchId managed in native (Kotlin)
|
|
397
|
-
- Direct removal from `ConcurrentHashMap`
|
|
398
|
-
- Automatic cleanup: stops LocationManager when last watch removed
|
|
399
|
-
|
|
400
|
-
**Key Difference:**
|
|
401
|
-
- **Bridge**: JS-only cleanup, native keeps running
|
|
402
|
-
- **Nitro**: Native cleanup + automatic resource management
|
|
105
|
+
### 2. iOS Setup
|
|
106
|
+
|
|
107
|
+
Add the following permissions to your **Info.plist**:
|
|
108
|
+
|
|
109
|
+
~~~xml
|
|
110
|
+
<key>NSLocationWhenInUseUsageDescription</key>
|
|
111
|
+
<string>This app requires access to your location while it’s in use.</string>
|
|
112
|
+
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
|
|
113
|
+
<string>This app requires access to your location at all times.</string>
|
|
114
|
+
~~~
|
|
403
115
|
|
|
404
116
|
---
|
|
405
117
|
|
|
406
|
-
###
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
-
|
|
419
|
-
|
|
420
|
-
- No cleanup of watch callbacks (handled in JS)
|
|
421
|
-
|
|
422
|
-
#### Nitro Architecture
|
|
423
|
-
```kotlin
|
|
424
|
-
// WatchPosition.kt
|
|
425
|
-
fun stopObserving() {
|
|
426
|
-
val locationManager = reactContext.getSystemService(Context.LOCATION_SERVICE) as? LocationManager
|
|
427
|
-
|
|
428
|
-
locationListener?.let { listener ->
|
|
429
|
-
locationManager?.removeUpdates(listener)
|
|
430
|
-
}
|
|
431
|
-
|
|
432
|
-
// Complete cleanup
|
|
433
|
-
locationListener = null
|
|
434
|
-
watchedProvider = null
|
|
435
|
-
currentOptions = null
|
|
436
|
-
watchCallbacks.clear()
|
|
437
|
-
}
|
|
438
|
-
```
|
|
439
|
-
|
|
440
|
-
**Additional cleanup:**
|
|
441
|
-
- All watch callbacks cleared from `ConcurrentHashMap`
|
|
442
|
-
- Explicit null assignment for GC
|
|
443
|
-
- Complete resource release
|
|
118
|
+
### 3. Android Setup
|
|
119
|
+
|
|
120
|
+
Add these permissions to your **AndroidManifest.xml**:
|
|
121
|
+
|
|
122
|
+
~~~xml
|
|
123
|
+
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
|
124
|
+
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
|
|
125
|
+
~~~
|
|
126
|
+
|
|
127
|
+
Optional (for background access):
|
|
128
|
+
|
|
129
|
+
~~~xml
|
|
130
|
+
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
|
|
131
|
+
~~~
|
|
444
132
|
|
|
445
133
|
---
|
|
446
134
|
|
|
447
|
-
|
|
135
|
+
### 4. Usage Example
|
|
448
136
|
|
|
449
|
-
|
|
137
|
+
~~~tsx
|
|
138
|
+
import Geolocation from 'react-native-nitro-geolocation';
|
|
450
139
|
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
140
|
+
Geolocation.getCurrentPosition(
|
|
141
|
+
(position) => {
|
|
142
|
+
console.log('Latitude:', position.coords.latitude);
|
|
143
|
+
console.log('Longitude:', position.coords.longitude);
|
|
144
|
+
},
|
|
145
|
+
(error) => {
|
|
146
|
+
console.error('Location error:', error);
|
|
147
|
+
},
|
|
148
|
+
{ enableHighAccuracy: true, timeout: 15000, maximumAge: 10000 }
|
|
149
|
+
);
|
|
150
|
+
|
|
151
|
+
// Subscribe to continuous updates
|
|
152
|
+
const watchId = Geolocation.watchPosition(
|
|
153
|
+
(position) => {
|
|
154
|
+
console.log('Updated position:', position);
|
|
155
|
+
},
|
|
156
|
+
(error) => console.error(error),
|
|
157
|
+
);
|
|
158
|
+
~~~
|
|
457
159
|
|
|
458
|
-
|
|
160
|
+
---
|
|
459
161
|
|
|
460
|
-
|
|
461
|
-
|-----------|--------|-------|
|
|
462
|
-
| Serialization buffers | ~1KB per call | 0 bytes (shared memory) |
|
|
463
|
-
| Event emitter registry | ~100 bytes per listener | 0 bytes (no event emitter) |
|
|
464
|
-
| Watch callback storage | JS Map (~50 bytes/watch) | ConcurrentHashMap (~40 bytes/watch) |
|
|
465
|
-
| JSON parsing overhead | ~500 bytes per location | 0 bytes |
|
|
162
|
+
### Migrating from `@react-native-community/geolocation`
|
|
466
163
|
|
|
467
|
-
|
|
164
|
+
Nitro Geolocation is **100% API-compatible** with the original package.
|
|
165
|
+
You can migrate simply by replacing imports:
|
|
468
166
|
|
|
469
|
-
|
|
167
|
+
~~~diff
|
|
168
|
+
- import Geolocation from '@react-native-community/geolocation';
|
|
169
|
+
+ import Geolocation from 'react-native-nitro-geolocation';
|
|
170
|
+
~~~
|
|
470
171
|
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
172
|
+
**Benefits:**
|
|
173
|
+
- Better performance via JSI
|
|
174
|
+
- Reduced bridge overhead
|
|
175
|
+
- Improved permission consistency
|
|
176
|
+
- Built-in TypeScript definitions
|
|
476
177
|
|
|
477
178
|
---
|
|
478
179
|
|
|
479
|
-
##
|
|
480
|
-
|
|
481
|
-
###
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
└─ JS callback execution (~1mW)
|
|
489
|
-
Total: ~11mW per update = 39.6J per hour
|
|
490
|
-
```
|
|
491
|
-
|
|
492
|
-
### Nitro Architecture
|
|
493
|
-
```
|
|
494
|
-
Location update (every 1s)
|
|
495
|
-
├─ GPS wakes CPU (~5mW)
|
|
496
|
-
├─ Direct callback (~0.1mW for 0.02ms)
|
|
497
|
-
└─ JS callback execution (~1mW)
|
|
498
|
-
Total: ~6.1mW per update = 22J per hour
|
|
499
|
-
```
|
|
500
|
-
|
|
501
|
-
**Battery savings**: ~45% less power consumption for continuous tracking
|
|
180
|
+
## 🧠 API Methods
|
|
181
|
+
|
|
182
|
+
### Summary
|
|
183
|
+
- `setRNConfiguration`
|
|
184
|
+
- `requestAuthorization`
|
|
185
|
+
- `getCurrentPosition`
|
|
186
|
+
- `watchPosition`
|
|
187
|
+
- `clearWatch`
|
|
188
|
+
- `stopObserving`
|
|
502
189
|
|
|
503
190
|
---
|
|
504
191
|
|
|
505
|
-
|
|
192
|
+
### `setRNConfiguration()`
|
|
193
|
+
|
|
194
|
+
Sets configuration options used for all location requests.
|
|
195
|
+
|
|
196
|
+
~~~tsx
|
|
197
|
+
import Geolocation from 'react-native-nitro-geolocation';
|
|
198
|
+
|
|
199
|
+
Geolocation.setRNConfiguration({
|
|
200
|
+
skipPermissionRequests: false,
|
|
201
|
+
authorizationLevel: 'auto',
|
|
202
|
+
enableBackgroundLocationUpdates: true,
|
|
203
|
+
locationProvider: 'auto',
|
|
204
|
+
});
|
|
506
205
|
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
| Java/Kotlin code | ~15KB | ~18KB |
|
|
510
|
-
| C++ code | 0KB | ~25KB (Nitro runtime) |
|
|
511
|
-
| JavaScript | ~8KB | ~6KB (less event handling) |
|
|
512
|
-
| **Total overhead** | ~23KB | ~49KB |
|
|
206
|
+
// recommended
|
|
207
|
+
import { setRNConfiguration } from 'react-native-nitro-geolocation';
|
|
513
208
|
|
|
514
|
-
|
|
209
|
+
setRNConfiguration({
|
|
210
|
+
skipPermissionRequests: false,
|
|
211
|
+
authorizationLevel: 'auto',
|
|
212
|
+
enableBackgroundLocationUpdates: true,
|
|
213
|
+
locationProvider: 'auto',
|
|
214
|
+
});
|
|
215
|
+
~~~
|
|
216
|
+
|
|
217
|
+
**Options:**
|
|
218
|
+
- `skipPermissionRequests` — default `false`
|
|
219
|
+
- `authorizationLevel` — `'always' | 'whenInUse' | 'auto'` *(iOS only)*
|
|
220
|
+
- `enableBackgroundLocationUpdates` — *(iOS only)*
|
|
221
|
+
- `locationProvider` — `'playServices' | 'android' | 'auto'` *(Android only)*
|
|
515
222
|
|
|
516
223
|
---
|
|
517
224
|
|
|
518
|
-
|
|
225
|
+
### `requestAuthorization()`
|
|
519
226
|
|
|
520
|
-
|
|
521
|
-
```typescript
|
|
522
|
-
// ❌ No compile-time safety
|
|
523
|
-
getCurrentPosition(
|
|
524
|
-
(position) => {
|
|
525
|
-
console.log(position.coords.latitude); // Could be undefined at runtime
|
|
526
|
-
}
|
|
527
|
-
);
|
|
528
|
-
```
|
|
227
|
+
Requests location permission from the system.
|
|
529
228
|
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
(
|
|
535
|
-
|
|
536
|
-
}
|
|
229
|
+
~~~tsx
|
|
230
|
+
import Geolocation from 'react-native-nitro-geolocation';
|
|
231
|
+
|
|
232
|
+
Geolocation.requestAuthorization(
|
|
233
|
+
() => console.log('Permission granted'),
|
|
234
|
+
(error) => console.error('Permission error:', error),
|
|
537
235
|
);
|
|
538
|
-
```
|
|
539
236
|
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
// Generated by Nitrogen
|
|
543
|
-
struct GeolocationResponse {
|
|
544
|
-
GeolocationCoordinates coords;
|
|
545
|
-
double timestamp;
|
|
546
|
-
};
|
|
547
|
-
```
|
|
237
|
+
// recommended
|
|
238
|
+
import { requestAuthorization } from 'react-native-nitro-geolocation';
|
|
548
239
|
|
|
549
|
-
|
|
240
|
+
requestAuthorization(
|
|
241
|
+
() => console.log('Permission granted'),
|
|
242
|
+
(error) => console.error('Permission error:', error),
|
|
243
|
+
);
|
|
244
|
+
~~~
|
|
550
245
|
|
|
551
246
|
---
|
|
552
247
|
|
|
553
|
-
|
|
248
|
+
### `getCurrentPosition()`
|
|
554
249
|
|
|
555
|
-
|
|
250
|
+
Retrieves the current device location once.
|
|
556
251
|
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
+ import Geolocation from 'react-native-nitro-geolocation';
|
|
252
|
+
~~~tsx
|
|
253
|
+
import Geolocation from 'react-native-nitro-geolocation';
|
|
560
254
|
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
{ enableHighAccuracy: true }
|
|
255
|
+
Geolocation.getCurrentPosition(
|
|
256
|
+
(position) => console.log(position),
|
|
257
|
+
(error) => console.error(error),
|
|
258
|
+
{ enableHighAccuracy: true, timeout: 15000, maximumAge: 10000 },
|
|
566
259
|
);
|
|
567
|
-
```
|
|
568
260
|
|
|
569
|
-
|
|
261
|
+
// recommended
|
|
262
|
+
import { getCurrentPosition } from 'react-native-nitro-geolocation';
|
|
263
|
+
|
|
264
|
+
getCurrentPosition(
|
|
265
|
+
(position) => console.log(position),
|
|
266
|
+
(error) => console.error(error),
|
|
267
|
+
{ enableHighAccuracy: true, timeout: 15000, maximumAge: 10000 },
|
|
268
|
+
);
|
|
269
|
+
~~~
|
|
570
270
|
|
|
571
271
|
---
|
|
572
272
|
|
|
573
|
-
|
|
273
|
+
### `watchPosition()`
|
|
574
274
|
|
|
575
|
-
|
|
576
|
-
2. **🔋 Battery**: ~45% less power consumption for continuous tracking
|
|
577
|
-
3. **🧵 Thread Safety**: Modern concurrent data structures (ConcurrentHashMap)
|
|
578
|
-
4. **🎯 Type Safety**: Compile-time type checking via C++
|
|
579
|
-
5. **🧹 Resource Management**: Automatic cleanup, explicit GC hints
|
|
580
|
-
6. **📦 Drop-in Replacement**: Zero migration cost
|
|
581
|
-
7. **🏗️ Modern Architecture**: JSI-based, ready for React Native's future
|
|
275
|
+
Watches location changes and calls the success callback each time.
|
|
582
276
|
|
|
583
|
-
|
|
277
|
+
~~~tsx
|
|
278
|
+
import Geolocation from 'react-native-nitro-geolocation';
|
|
279
|
+
|
|
280
|
+
const id = Geolocation.watchPosition(
|
|
281
|
+
(position) => console.log('Position:', position),
|
|
282
|
+
(error) => console.error(error),
|
|
283
|
+
{ interval: 5000, distanceFilter: 10 },
|
|
284
|
+
);
|
|
285
|
+
|
|
286
|
+
// recommended
|
|
287
|
+
import { watchPosition } from 'react-native-nitro-geolocation';
|
|
584
288
|
|
|
585
|
-
|
|
289
|
+
const id = watchPosition(
|
|
290
|
+
(position) => console.log('Position:', position),
|
|
291
|
+
(error) => console.error(error),
|
|
292
|
+
{ interval: 5000, distanceFilter: 10 },
|
|
293
|
+
);
|
|
586
294
|
|
|
587
|
-
|
|
295
|
+
~~~
|
|
588
296
|
|
|
589
297
|
---
|
|
590
298
|
|
|
591
|
-
|
|
299
|
+
### `clearWatch()`
|
|
300
|
+
|
|
301
|
+
Stops watching location updates for a given watch ID.
|
|
592
302
|
|
|
593
|
-
|
|
303
|
+
~~~tsx
|
|
304
|
+
import Geolocation from 'react-native-nitro-geolocation';
|
|
305
|
+
Geolocation.clearWatch(id);
|
|
306
|
+
|
|
307
|
+
// recommended
|
|
308
|
+
import { clearWatch } from 'react-native-nitro-geolocation';
|
|
309
|
+
clearWatch(id);
|
|
310
|
+
~~~
|
|
311
|
+
|
|
312
|
+
---
|
|
594
313
|
|
|
595
|
-
|
|
596
|
-
Modified work Copyright (c) 2025, jingjing2222
|
|
314
|
+
## 🧪 Summary
|
|
597
315
|
|
|
598
|
-
|
|
316
|
+
**React Native Nitro Geolocation** transforms the geolocation API
|
|
317
|
+
from a bridge-based, event-driven system into a **JSI-powered direct-callback model** —
|
|
318
|
+
delivering native-level performance with **zero API changes** for developers.
|