react-native-nitro-geolocation 0.0.1 → 0.1.0

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 (79) hide show
  1. package/LICENSE +4 -1
  2. package/README.md +598 -0
  3. package/android/src/main/java/com/margelo/nitro/nitrogeolocation/GetCurrentPosition.kt +341 -0
  4. package/android/src/main/java/com/margelo/nitro/nitrogeolocation/NitroGeolocation.kt +76 -5
  5. package/android/src/main/java/com/margelo/nitro/nitrogeolocation/RequestAuthorization.kt +164 -0
  6. package/android/src/main/java/com/margelo/nitro/nitrogeolocation/WatchPosition.kt +228 -0
  7. package/ios/LocationManager.swift +529 -0
  8. package/ios/NitroGeolocation.swift +96 -2
  9. package/nitrogen/generated/.gitattributes +1 -0
  10. package/nitrogen/generated/android/c++/JAuthorizationLevelInternal.hpp +62 -0
  11. package/nitrogen/generated/android/c++/JFunc_void.hpp +74 -0
  12. package/nitrogen/generated/android/c++/JFunc_void_GeolocationError.hpp +77 -0
  13. package/nitrogen/generated/android/c++/JFunc_void_GeolocationResponse.hpp +79 -0
  14. package/nitrogen/generated/android/c++/JGeolocationCoordinates.hpp +77 -0
  15. package/nitrogen/generated/android/c++/JGeolocationError.hpp +69 -0
  16. package/nitrogen/generated/android/c++/JGeolocationOptions.hpp +77 -0
  17. package/nitrogen/generated/android/c++/JGeolocationResponse.hpp +59 -0
  18. package/nitrogen/generated/android/c++/JHybridNitroGeolocationSpec.cpp +98 -0
  19. package/nitrogen/generated/android/c++/JHybridNitroGeolocationSpec.hpp +69 -0
  20. package/nitrogen/generated/android/c++/JLocationProviderInternal.hpp +62 -0
  21. package/nitrogen/generated/android/c++/JRNConfigurationInternal.hpp +69 -0
  22. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/AuthorizationLevelInternal.kt +22 -0
  23. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/Func_void.kt +81 -0
  24. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/Func_void_GeolocationError.kt +81 -0
  25. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/Func_void_GeolocationResponse.kt +81 -0
  26. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/GeolocationCoordinates.kt +47 -0
  27. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/GeolocationError.kt +41 -0
  28. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/GeolocationOptions.kt +47 -0
  29. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/GeolocationResponse.kt +32 -0
  30. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/HybridNitroGeolocationSpec.kt +87 -0
  31. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/LocationProviderInternal.kt +22 -0
  32. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/RNConfigurationInternal.kt +38 -0
  33. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/nitrogeolocationOnLoad.kt +35 -0
  34. package/nitrogen/generated/android/nitrogeolocation+autolinking.cmake +81 -0
  35. package/nitrogen/generated/android/nitrogeolocation+autolinking.gradle +27 -0
  36. package/nitrogen/generated/android/nitrogeolocationOnLoad.cpp +50 -0
  37. package/nitrogen/generated/android/nitrogeolocationOnLoad.hpp +25 -0
  38. package/nitrogen/generated/ios/NitroGeolocation+autolinking.rb +60 -0
  39. package/nitrogen/generated/ios/NitroGeolocation-Swift-Cxx-Bridge.cpp +56 -0
  40. package/nitrogen/generated/ios/NitroGeolocation-Swift-Cxx-Bridge.hpp +252 -0
  41. package/nitrogen/generated/ios/NitroGeolocation-Swift-Cxx-Umbrella.hpp +67 -0
  42. package/nitrogen/generated/ios/NitroGeolocationAutolinking.mm +33 -0
  43. package/nitrogen/generated/ios/NitroGeolocationAutolinking.swift +25 -0
  44. package/nitrogen/generated/ios/c++/HybridNitroGeolocationSpecSwift.cpp +11 -0
  45. package/nitrogen/generated/ios/c++/HybridNitroGeolocationSpecSwift.hpp +125 -0
  46. package/nitrogen/generated/ios/swift/AuthorizationLevelInternal.swift +44 -0
  47. package/nitrogen/generated/ios/swift/Func_void.swift +47 -0
  48. package/nitrogen/generated/ios/swift/Func_void_GeolocationError.swift +47 -0
  49. package/nitrogen/generated/ios/swift/Func_void_GeolocationResponse.swift +47 -0
  50. package/nitrogen/generated/ios/swift/GeolocationCoordinates.swift +149 -0
  51. package/nitrogen/generated/ios/swift/GeolocationError.swift +79 -0
  52. package/nitrogen/generated/ios/swift/GeolocationOptions.swift +185 -0
  53. package/nitrogen/generated/ios/swift/GeolocationResponse.swift +46 -0
  54. package/nitrogen/generated/ios/swift/HybridNitroGeolocationSpec.swift +54 -0
  55. package/nitrogen/generated/ios/swift/HybridNitroGeolocationSpec_cxx.swift +236 -0
  56. package/nitrogen/generated/ios/swift/LocationProviderInternal.swift +44 -0
  57. package/nitrogen/generated/ios/swift/RNConfigurationInternal.swift +104 -0
  58. package/nitrogen/generated/shared/c++/AuthorizationLevelInternal.hpp +80 -0
  59. package/nitrogen/generated/shared/c++/GeolocationCoordinates.hpp +91 -0
  60. package/nitrogen/generated/shared/c++/GeolocationError.hpp +83 -0
  61. package/nitrogen/generated/shared/c++/GeolocationOptions.hpp +91 -0
  62. package/nitrogen/generated/shared/c++/GeolocationResponse.hpp +72 -0
  63. package/nitrogen/generated/shared/c++/HybridNitroGeolocationSpec.cpp +26 -0
  64. package/nitrogen/generated/shared/c++/HybridNitroGeolocationSpec.hpp +79 -0
  65. package/nitrogen/generated/shared/c++/LocationProviderInternal.hpp +80 -0
  66. package/nitrogen/generated/shared/c++/RNConfigurationInternal.hpp +84 -0
  67. package/package.json +34 -10
  68. package/src/NitroGeolocation.nitro.ts +38 -3
  69. package/src/NitroGeolocationModule.ts +5 -0
  70. package/src/clearWatch.ts +13 -0
  71. package/src/getCurrentPosition.ts +14 -0
  72. package/src/index.tsx +32 -7
  73. package/src/requestAuthorization.ts +9 -0
  74. package/src/setRNConfiguration.ts +22 -0
  75. package/src/stopObserving.ts +12 -0
  76. package/src/types.ts +43 -0
  77. package/src/watchPosition.ts +26 -0
  78. package/nitro.json +0 -17
  79. package/turbo.json +0 -42
@@ -0,0 +1,228 @@
1
+ package com.margelo.nitro.nitrogeolocation
2
+
3
+ import android.Manifest
4
+ import android.content.Context
5
+ import android.content.pm.PackageManager
6
+ import android.location.Location
7
+ import android.location.LocationListener
8
+ import android.location.LocationManager
9
+ import android.os.Bundle
10
+ import android.os.Looper
11
+ import android.util.Log
12
+ import androidx.core.content.ContextCompat
13
+ import com.facebook.react.bridge.ReactApplicationContext
14
+ import java.util.concurrent.ConcurrentHashMap
15
+ import java.util.concurrent.atomic.AtomicInteger
16
+
17
+ class WatchPosition(private val reactContext: ReactApplicationContext) {
18
+
19
+ private val watchCallbacks = ConcurrentHashMap<Int, WatchCallback>()
20
+ private val watchIdGenerator = AtomicInteger(0)
21
+ private var locationListener: LocationListener? = null
22
+ private var watchedProvider: String? = null
23
+ private var currentOptions: GeolocationOptions? = null
24
+
25
+ data class WatchCallback(
26
+ val success: (GeolocationResponse) -> Unit,
27
+ val error: ((GeolocationError) -> Unit)?,
28
+ val options: GeolocationOptions?
29
+ )
30
+
31
+ fun watch(
32
+ success: (GeolocationResponse) -> Unit,
33
+ error: ((GeolocationError) -> Unit)?,
34
+ options: GeolocationOptions?
35
+ ): Int {
36
+ val watchId = watchIdGenerator.incrementAndGet()
37
+ watchCallbacks[watchId] = WatchCallback(success, error, options)
38
+
39
+ // Start observing if this is the first watch
40
+ if (watchCallbacks.size == 1) {
41
+ startObserving(options)
42
+ }
43
+
44
+ return watchId
45
+ }
46
+
47
+ fun clearWatch(watchId: Int) {
48
+ watchCallbacks.remove(watchId)
49
+
50
+ // Stop observing if no more watches
51
+ if (watchCallbacks.isEmpty()) {
52
+ stopObserving()
53
+ }
54
+ }
55
+
56
+ fun stopObserving() {
57
+ val locationManager =
58
+ reactContext.getSystemService(Context.LOCATION_SERVICE) as? LocationManager
59
+
60
+ locationListener?.let { listener -> locationManager?.removeUpdates(listener) }
61
+
62
+ locationListener = null
63
+ watchedProvider = null
64
+ currentOptions = null
65
+ watchCallbacks.clear()
66
+ }
67
+
68
+ private fun startObserving(options: GeolocationOptions?) {
69
+ val locationManager =
70
+ reactContext.getSystemService(Context.LOCATION_SERVICE) as? LocationManager
71
+
72
+ if (locationManager == null) {
73
+ Log.e(TAG, "LocationManager is not available")
74
+ emitErrorToAll(
75
+ createError(
76
+ GetCurrentPosition.POSITION_UNAVAILABLE,
77
+ "LocationManager is not available"
78
+ )
79
+ )
80
+ return
81
+ }
82
+
83
+ val opts = parseOptions(options)
84
+ val provider = getValidProvider(locationManager, opts.enableHighAccuracy)
85
+
86
+ if (provider == null) {
87
+ Log.e(TAG, "No location provider available")
88
+ emitErrorToAll(
89
+ createError(
90
+ GetCurrentPosition.POSITION_UNAVAILABLE,
91
+ "No location provider available"
92
+ )
93
+ )
94
+ return
95
+ }
96
+
97
+ // If already watching with the same provider, don't restart
98
+ if (provider == watchedProvider) {
99
+ return
100
+ }
101
+
102
+ try {
103
+ // Remove old listener if exists
104
+ locationListener?.let { locationManager.removeUpdates(it) }
105
+
106
+ // Create new listener
107
+ val listener =
108
+ object : LocationListener {
109
+ override fun onLocationChanged(location: Location) {
110
+ val position = locationToPosition(location)
111
+ // Call all watch callbacks
112
+ watchCallbacks.values.forEach { callback -> callback.success(position) }
113
+ }
114
+
115
+ override fun onStatusChanged(
116
+ provider: String?,
117
+ status: Int,
118
+ extras: Bundle?
119
+ ) {}
120
+ override fun onProviderEnabled(provider: String) {}
121
+ override fun onProviderDisabled(provider: String) {}
122
+ }
123
+
124
+ locationManager.requestLocationUpdates(
125
+ provider,
126
+ opts.interval.toLong(),
127
+ opts.distanceFilter.toFloat(),
128
+ listener,
129
+ Looper.getMainLooper()
130
+ )
131
+
132
+ locationListener = listener
133
+ watchedProvider = provider
134
+ currentOptions = options
135
+ } catch (e: SecurityException) {
136
+ Log.e(TAG, "SecurityException: ${e.message}")
137
+ emitErrorToAll(
138
+ createError(
139
+ GetCurrentPosition.PERMISSION_DENIED,
140
+ "Location permission denied: ${e.message}"
141
+ )
142
+ )
143
+ }
144
+ }
145
+
146
+ private fun emitErrorToAll(error: GeolocationError) {
147
+ watchCallbacks.values.forEach { callback -> callback.error?.invoke(error) }
148
+ }
149
+
150
+ private fun parseOptions(options: GeolocationOptions?): ParsedOptions {
151
+ return ParsedOptions(
152
+ interval = options?.interval ?: DEFAULT_INTERVAL,
153
+ distanceFilter = options?.distanceFilter ?: DEFAULT_DISTANCE_FILTER,
154
+ enableHighAccuracy = options?.enableHighAccuracy ?: false
155
+ )
156
+ }
157
+
158
+ private fun getValidProvider(locationManager: LocationManager, highAccuracy: Boolean): String? {
159
+ val preferredProvider =
160
+ if (highAccuracy) LocationManager.GPS_PROVIDER else LocationManager.NETWORK_PROVIDER
161
+ val fallbackProvider =
162
+ if (highAccuracy) LocationManager.NETWORK_PROVIDER else LocationManager.GPS_PROVIDER
163
+
164
+ return when {
165
+ isProviderValid(locationManager, preferredProvider) -> preferredProvider
166
+ isProviderValid(locationManager, fallbackProvider) -> fallbackProvider
167
+ else -> null
168
+ }
169
+ }
170
+
171
+ private fun isProviderValid(locationManager: LocationManager, provider: String): Boolean {
172
+ if (!locationManager.isProviderEnabled(provider)) return false
173
+
174
+ val permission =
175
+ if (provider == LocationManager.GPS_PROVIDER)
176
+ Manifest.permission.ACCESS_FINE_LOCATION
177
+ else Manifest.permission.ACCESS_COARSE_LOCATION
178
+
179
+ return ContextCompat.checkSelfPermission(reactContext, permission) ==
180
+ PackageManager.PERMISSION_GRANTED
181
+ }
182
+
183
+ private fun locationToPosition(location: Location): GeolocationResponse {
184
+ return GeolocationResponse(
185
+ coords =
186
+ GeolocationCoordinates(
187
+ latitude = location.latitude,
188
+ longitude = location.longitude,
189
+ altitude = if (location.hasAltitude()) location.altitude else null,
190
+ accuracy = location.accuracy.toDouble(),
191
+ altitudeAccuracy =
192
+ if (android.os.Build.VERSION.SDK_INT >=
193
+ android.os.Build.VERSION_CODES.O &&
194
+ location.hasVerticalAccuracy()
195
+ )
196
+ location.verticalAccuracyMeters.toDouble()
197
+ else null,
198
+ heading =
199
+ if (location.hasBearing()) location.bearing.toDouble()
200
+ else null,
201
+ speed = if (location.hasSpeed()) location.speed.toDouble() else null
202
+ ),
203
+ timestamp = location.time.toDouble()
204
+ )
205
+ }
206
+
207
+ private fun createError(code: Int, message: String): GeolocationError {
208
+ return GeolocationError(
209
+ code = code.toDouble(),
210
+ message = message,
211
+ PERMISSION_DENIED = GetCurrentPosition.PERMISSION_DENIED.toDouble(),
212
+ POSITION_UNAVAILABLE = GetCurrentPosition.POSITION_UNAVAILABLE.toDouble(),
213
+ TIMEOUT = GetCurrentPosition.TIMEOUT.toDouble()
214
+ )
215
+ }
216
+
217
+ private data class ParsedOptions(
218
+ val interval: Double,
219
+ val distanceFilter: Double,
220
+ val enableHighAccuracy: Boolean
221
+ )
222
+
223
+ companion object {
224
+ private const val TAG = "WatchPosition"
225
+ const val DEFAULT_INTERVAL = 1000.0 // 1 second
226
+ const val DEFAULT_DISTANCE_FILTER = 100.0 // 100 meters
227
+ }
228
+ }