react-native-nitro-geolocation 0.1.1 → 0.2.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.
- package/android/src/main/java/com/margelo/nitro/nitrogeolocation/GetCurrentPosition.kt +4 -4
- package/android/src/main/java/com/margelo/nitro/nitrogeolocation/NitroGeolocation.kt +642 -50
- package/android/src/main/java/com/margelo/nitro/nitrogeolocation/NitroGeolocationCompat.kt +81 -0
- package/android/src/main/java/com/margelo/nitro/nitrogeolocation/WatchPosition.kt +4 -4
- package/ios/LocationManager.swift +113 -128
- package/ios/NitroGeolocation.swift +546 -61
- package/ios/NitroGeolocationCompat.swift +109 -0
- package/nitrogen/generated/android/c++/JAuthorizationLevel.hpp +61 -0
- package/nitrogen/generated/android/c++/JAuthorizationLevelInternal.hpp +3 -4
- package/nitrogen/generated/android/c++/JFunc_void.hpp +2 -1
- package/nitrogen/generated/android/c++/JFunc_void_GeolocationError.hpp +2 -1
- package/nitrogen/generated/android/c++/JFunc_void_GeolocationResponse.hpp +6 -1
- package/nitrogen/generated/android/c++/JFunc_void_LocationError.hpp +78 -0
- package/nitrogen/generated/android/c++/JGeolocationCoordinates.hpp +25 -17
- package/nitrogen/generated/android/c++/JGeolocationError.hpp +5 -1
- package/nitrogen/generated/android/c++/JGeolocationOptions.hpp +5 -1
- package/nitrogen/generated/android/c++/JGeolocationResponse.hpp +9 -1
- package/nitrogen/generated/android/c++/JHybridNitroGeolocationCompatSpec.cpp +109 -0
- package/nitrogen/generated/android/c++/JHybridNitroGeolocationCompatSpec.hpp +70 -0
- package/nitrogen/generated/android/c++/JHybridNitroGeolocationSpec.cpp +98 -42
- package/nitrogen/generated/android/c++/JHybridNitroGeolocationSpec.hpp +7 -5
- package/nitrogen/generated/android/c++/JLocationError.hpp +61 -0
- package/nitrogen/generated/android/c++/JLocationProvider.hpp +61 -0
- package/nitrogen/generated/android/c++/JLocationProviderInternal.hpp +3 -4
- package/nitrogen/generated/android/c++/JLocationRequestOptions.hpp +81 -0
- package/nitrogen/generated/android/c++/JModernGeolocationConfiguration.hpp +73 -0
- package/nitrogen/generated/android/c++/JNullableDouble.cpp +26 -0
- package/nitrogen/generated/android/c++/JNullableDouble.hpp +69 -0
- package/nitrogen/generated/android/c++/JPermissionStatus.hpp +64 -0
- package/nitrogen/generated/android/c++/JRNConfigurationInternal.hpp +5 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/AuthorizationLevel.kt +24 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/AuthorizationLevelInternal.kt +2 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/Func_void.kt +0 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/Func_void_GeolocationError.kt +0 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/Func_void_GeolocationResponse.kt +0 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/Func_void_LocationError.kt +80 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/GeolocationCoordinates.kt +34 -25
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/GeolocationError.kt +27 -18
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/GeolocationOptions.kt +33 -24
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/GeolocationResponse.kt +18 -9
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/HybridNitroGeolocationCompatSpec.kt +92 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/HybridNitroGeolocationSpec.kt +17 -17
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/LocationError.kt +41 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/LocationProvider.kt +24 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/LocationProviderInternal.kt +2 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/LocationRequestOptions.kt +56 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/ModernGeolocationConfiguration.kt +47 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/NullableDouble.kt +59 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/PermissionStatus.kt +25 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/RNConfigurationInternal.kt +24 -15
- package/nitrogen/generated/android/nitrogeolocation+autolinking.cmake +3 -0
- package/nitrogen/generated/android/nitrogeolocationOnLoad.cpp +14 -2
- package/nitrogen/generated/ios/NitroGeolocation+autolinking.rb +1 -1
- package/nitrogen/generated/ios/NitroGeolocation-Swift-Cxx-Bridge.cpp +55 -13
- package/nitrogen/generated/ios/NitroGeolocation-Swift-Cxx-Bridge.hpp +325 -68
- package/nitrogen/generated/ios/NitroGeolocation-Swift-Cxx-Umbrella.hpp +26 -0
- package/nitrogen/generated/ios/NitroGeolocationAutolinking.mm +8 -0
- package/nitrogen/generated/ios/NitroGeolocationAutolinking.swift +15 -0
- package/nitrogen/generated/ios/c++/HybridNitroGeolocationCompatSpecSwift.cpp +11 -0
- package/nitrogen/generated/ios/c++/HybridNitroGeolocationCompatSpecSwift.hpp +130 -0
- package/nitrogen/generated/ios/c++/HybridNitroGeolocationSpecSwift.hpp +47 -26
- package/nitrogen/generated/ios/swift/AuthorizationLevel.swift +44 -0
- package/nitrogen/generated/ios/swift/Func_void.swift +1 -1
- package/nitrogen/generated/ios/swift/Func_void_GeolocationError.swift +1 -1
- package/nitrogen/generated/ios/swift/Func_void_GeolocationResponse.swift +1 -1
- package/nitrogen/generated/ios/swift/Func_void_LocationError.swift +47 -0
- package/nitrogen/generated/ios/swift/Func_void_PermissionStatus.swift +47 -0
- package/nitrogen/generated/ios/swift/Func_void_std__exception_ptr.swift +47 -0
- package/nitrogen/generated/ios/swift/GeolocationCoordinates.swift +132 -93
- package/nitrogen/generated/ios/swift/GeolocationError.swift +11 -40
- package/nitrogen/generated/ios/swift/GeolocationOptions.swift +29 -98
- package/nitrogen/generated/ios/swift/GeolocationResponse.swift +5 -16
- package/nitrogen/generated/ios/swift/HybridNitroGeolocationCompatSpec.swift +61 -0
- package/nitrogen/generated/ios/swift/HybridNitroGeolocationCompatSpec_cxx.swift +244 -0
- package/nitrogen/generated/ios/swift/HybridNitroGeolocationSpec.swift +13 -5
- package/nitrogen/generated/ios/swift/HybridNitroGeolocationSpec_cxx.swift +66 -64
- package/nitrogen/generated/ios/swift/LocationError.swift +35 -0
- package/nitrogen/generated/ios/swift/LocationProvider.swift +44 -0
- package/nitrogen/generated/ios/swift/LocationRequestOptions.swift +116 -0
- package/nitrogen/generated/ios/swift/ModernGeolocationConfiguration.swift +83 -0
- package/nitrogen/generated/ios/swift/NullableDouble.swift +18 -0
- package/nitrogen/generated/ios/swift/PermissionStatus.swift +48 -0
- package/nitrogen/generated/ios/swift/RNConfigurationInternal.swift +16 -50
- package/nitrogen/generated/shared/c++/AuthorizationLevel.hpp +80 -0
- package/nitrogen/generated/shared/c++/GeolocationCoordinates.hpp +45 -27
- package/nitrogen/generated/shared/c++/GeolocationError.hpp +32 -16
- package/nitrogen/generated/shared/c++/GeolocationOptions.hpp +38 -22
- package/nitrogen/generated/shared/c++/GeolocationResponse.hpp +23 -7
- package/nitrogen/generated/shared/c++/HybridNitroGeolocationCompatSpec.cpp +26 -0
- package/nitrogen/generated/shared/c++/HybridNitroGeolocationCompatSpec.hpp +79 -0
- package/nitrogen/generated/shared/c++/HybridNitroGeolocationSpec.cpp +4 -3
- package/nitrogen/generated/shared/c++/HybridNitroGeolocationSpec.hpp +22 -16
- package/nitrogen/generated/shared/c++/LocationError.hpp +87 -0
- package/nitrogen/generated/shared/c++/LocationProvider.hpp +80 -0
- package/nitrogen/generated/shared/c++/LocationRequestOptions.hpp +107 -0
- package/nitrogen/generated/shared/c++/ModernGeolocationConfiguration.hpp +100 -0
- package/nitrogen/generated/shared/c++/PermissionStatus.hpp +84 -0
- package/nitrogen/generated/shared/c++/RNConfigurationInternal.hpp +29 -13
- package/package.json +16 -7
- package/src/GeolocationClient.ts +116 -0
- package/src/NitroGeolocation.nitro.ts +177 -30
- package/src/NitroGeolocationCompat.nitro.ts +41 -0
- package/src/NitroGeolocationModule.ts +6 -0
- package/src/compat/clearWatch.ts +9 -0
- package/src/{getCurrentPosition.ts → compat/getCurrentPosition.ts} +7 -3
- package/src/compat/index.tsx +34 -0
- package/src/compat/requestAuthorization.ts +9 -0
- package/src/{setRNConfiguration.ts → compat/setRNConfiguration.ts} +6 -4
- package/src/{stopObserving.ts → compat/stopObserving.ts} +4 -2
- package/src/{watchPosition.ts → compat/watchPosition.ts} +7 -6
- package/src/components/GeolocationProvider.tsx +91 -0
- package/src/components/index.ts +13 -0
- package/src/hooks/index.ts +9 -0
- package/src/hooks/useCheckPermission.ts +46 -0
- package/src/hooks/useGetCurrentPosition.ts +44 -0
- package/src/hooks/useRequestPermission.ts +38 -0
- package/src/hooks/useWatchPosition.ts +127 -0
- package/src/index.tsx +72 -27
- package/src/types.ts +32 -4
- package/src/utils/cache.ts +25 -0
- package/src/utils/config.ts +93 -0
- package/src/utils/errors.ts +82 -0
- package/src/utils/index.ts +27 -0
- package/src/utils/provider.ts +61 -0
- package/src/utils/quality.ts +98 -0
- package/README.md +0 -318
- package/src/clearWatch.ts +0 -13
- package/src/requestAuthorization.ts +0 -9
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
package com.margelo.nitro.nitrogeolocation
|
|
2
|
+
|
|
3
|
+
import com.facebook.proguard.annotations.DoNotStrip
|
|
4
|
+
import com.facebook.react.bridge.ReactApplicationContext
|
|
5
|
+
import com.margelo.nitro.NitroModules
|
|
6
|
+
|
|
7
|
+
@DoNotStrip
|
|
8
|
+
class NitroGeolocationCompat(
|
|
9
|
+
private val reactContext: ReactApplicationContext = NitroModules.applicationContext!!
|
|
10
|
+
) : HybridNitroGeolocationCompatSpec() {
|
|
11
|
+
private var configuration: RNConfigurationInternal =
|
|
12
|
+
RNConfigurationInternal(
|
|
13
|
+
skipPermissionRequests = false,
|
|
14
|
+
authorizationLevel = null,
|
|
15
|
+
enableBackgroundLocationUpdates = null,
|
|
16
|
+
locationProvider = null
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
private val requestAuthorizationHandler by lazy {
|
|
20
|
+
RequestAuthorization(
|
|
21
|
+
reactContext = reactContext,
|
|
22
|
+
onPermissionResult = { result, success, error ->
|
|
23
|
+
when (result) {
|
|
24
|
+
is PermissionResult.Granted -> success?.invoke()
|
|
25
|
+
is PermissionResult.Denied ->
|
|
26
|
+
error?.invoke(
|
|
27
|
+
createPermissionError(
|
|
28
|
+
"Location permission was not granted."
|
|
29
|
+
)
|
|
30
|
+
)
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
private val watchPositionHandler by lazy { WatchPosition(reactContext) }
|
|
37
|
+
|
|
38
|
+
override fun setRNConfiguration(config: RNConfigurationInternal) {
|
|
39
|
+
configuration = config
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
override fun requestAuthorization(
|
|
43
|
+
success: (() -> Unit)?,
|
|
44
|
+
error: ((error: GeolocationError) -> Unit)?
|
|
45
|
+
) {
|
|
46
|
+
requestAuthorizationHandler.execute(success, error)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
override fun getCurrentPosition(
|
|
50
|
+
success: (position: GeolocationResponse) -> Unit,
|
|
51
|
+
error: ((error: GeolocationError) -> Unit)?,
|
|
52
|
+
options: GeolocationOptions?
|
|
53
|
+
) {
|
|
54
|
+
GetCurrentPosition(reactContext).execute(success, error, options)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
override fun watchPosition(
|
|
58
|
+
success: (position: GeolocationResponse) -> Unit,
|
|
59
|
+
error: ((error: GeolocationError) -> Unit)?,
|
|
60
|
+
options: GeolocationOptions?
|
|
61
|
+
): Double {
|
|
62
|
+
return watchPositionHandler.watch(success, error, options).toDouble()
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
override fun clearWatch(watchId: Double) {
|
|
66
|
+
watchPositionHandler.clearWatch(watchId.toInt())
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
override fun stopObserving() {
|
|
70
|
+
watchPositionHandler.stopObserving()
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
private fun createPermissionError(message: String) =
|
|
74
|
+
GeolocationError(
|
|
75
|
+
code = RequestAuthorization.PERMISSION_DENIED.toDouble(),
|
|
76
|
+
message = message,
|
|
77
|
+
PERMISSION_DENIED = RequestAuthorization.PERMISSION_DENIED.toDouble(),
|
|
78
|
+
POSITION_UNAVAILABLE = RequestAuthorization.POSITION_UNAVAILABLE.toDouble(),
|
|
79
|
+
TIMEOUT = RequestAuthorization.TIMEOUT.toDouble()
|
|
80
|
+
)
|
|
81
|
+
}
|
|
@@ -186,19 +186,19 @@ class WatchPosition(private val reactContext: ReactApplicationContext) {
|
|
|
186
186
|
GeolocationCoordinates(
|
|
187
187
|
latitude = location.latitude,
|
|
188
188
|
longitude = location.longitude,
|
|
189
|
-
altitude = if (location.hasAltitude()) location.altitude else null,
|
|
189
|
+
altitude = if (location.hasAltitude()) NullableDouble.create(location.altitude) else null,
|
|
190
190
|
accuracy = location.accuracy.toDouble(),
|
|
191
191
|
altitudeAccuracy =
|
|
192
192
|
if (android.os.Build.VERSION.SDK_INT >=
|
|
193
193
|
android.os.Build.VERSION_CODES.O &&
|
|
194
194
|
location.hasVerticalAccuracy()
|
|
195
195
|
)
|
|
196
|
-
location.verticalAccuracyMeters.toDouble()
|
|
196
|
+
NullableDouble.create(location.verticalAccuracyMeters.toDouble())
|
|
197
197
|
else null,
|
|
198
198
|
heading =
|
|
199
|
-
if (location.hasBearing()) location.bearing.toDouble()
|
|
199
|
+
if (location.hasBearing()) NullableDouble.create(location.bearing.toDouble())
|
|
200
200
|
else null,
|
|
201
|
-
speed = if (location.hasSpeed()) location.speed.toDouble() else null
|
|
201
|
+
speed = if (location.hasSpeed()) NullableDouble.create(location.speed.toDouble()) else null
|
|
202
202
|
),
|
|
203
203
|
timestamp = location.time.toDouble()
|
|
204
204
|
)
|
|
@@ -10,10 +10,11 @@ class LocationManager: NSObject, CLLocationManagerDelegate {
|
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
private struct LocationRequest {
|
|
13
|
+
let id: UUID = UUID()
|
|
13
14
|
let success: (GeolocationResponse) -> Void
|
|
14
15
|
let error: ((GeolocationError) -> Void)?
|
|
15
16
|
let options: ParsedOptions
|
|
16
|
-
var timer:
|
|
17
|
+
var timer: DispatchSourceTimer?
|
|
17
18
|
}
|
|
18
19
|
|
|
19
20
|
private struct WatchSubscription {
|
|
@@ -22,7 +23,7 @@ class LocationManager: NSObject, CLLocationManagerDelegate {
|
|
|
22
23
|
let options: ParsedOptions
|
|
23
24
|
}
|
|
24
25
|
|
|
25
|
-
|
|
26
|
+
struct ParsedOptions {
|
|
26
27
|
let timeout: Double
|
|
27
28
|
let maximumAge: Double
|
|
28
29
|
let accuracy: CLLocationAccuracy
|
|
@@ -51,7 +52,7 @@ class LocationManager: NSObject, CLLocationManagerDelegate {
|
|
|
51
52
|
// MARK: - Properties
|
|
52
53
|
|
|
53
54
|
private var locationManager: CLLocationManager?
|
|
54
|
-
private var lastLocation: CLLocation?
|
|
55
|
+
internal private(set) var lastLocation: CLLocation?
|
|
55
56
|
private var usingSignificantChanges: Bool = false
|
|
56
57
|
|
|
57
58
|
// Authorization
|
|
@@ -84,36 +85,32 @@ class LocationManager: NSObject, CLLocationManagerDelegate {
|
|
|
84
85
|
success: (() -> Void)?,
|
|
85
86
|
error: ((GeolocationError) -> Void)?
|
|
86
87
|
) {
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
self.initializeLocationManagerIfNeeded()
|
|
91
|
-
self.enqueueAuthorizationCallbacks(success: success, error: error)
|
|
92
|
-
|
|
93
|
-
// Skip permission requests if configured
|
|
94
|
-
if skipPermissionRequests {
|
|
95
|
-
if enableBackgroundLocationUpdates {
|
|
96
|
-
self.enableBackgroundLocationUpdatesIfNeeded()
|
|
97
|
-
}
|
|
98
|
-
self.handleAuthorizationSuccess()
|
|
99
|
-
return
|
|
100
|
-
}
|
|
88
|
+
initializeLocationManagerIfNeeded()
|
|
89
|
+
enqueueAuthorizationCallbacks(success: success, error: error)
|
|
101
90
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
if
|
|
105
|
-
|
|
106
|
-
return
|
|
91
|
+
// Skip permission requests if configured
|
|
92
|
+
if skipPermissionRequests {
|
|
93
|
+
if enableBackgroundLocationUpdates {
|
|
94
|
+
enableBackgroundLocationUpdatesIfNeeded()
|
|
107
95
|
}
|
|
96
|
+
handleAuthorizationSuccess()
|
|
97
|
+
return
|
|
98
|
+
}
|
|
108
99
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
100
|
+
// Check if already authorized
|
|
101
|
+
let currentStatus = CLLocationManager.authorizationStatus()
|
|
102
|
+
if currentStatus == .authorizedAlways || currentStatus == .authorizedWhenInUse {
|
|
103
|
+
handleAuthorizationSuccess()
|
|
104
|
+
return
|
|
105
|
+
}
|
|
113
106
|
|
|
114
|
-
|
|
115
|
-
|
|
107
|
+
if currentStatus == .denied || currentStatus == .restricted {
|
|
108
|
+
handleAuthorizationError(for: currentStatus)
|
|
109
|
+
return
|
|
116
110
|
}
|
|
111
|
+
|
|
112
|
+
// Not determined yet, request permission
|
|
113
|
+
requestPermission(for: authType)
|
|
117
114
|
}
|
|
118
115
|
|
|
119
116
|
private func enqueueAuthorizationCallbacks(
|
|
@@ -153,63 +150,51 @@ class LocationManager: NSObject, CLLocationManagerDelegate {
|
|
|
153
150
|
error: ((GeolocationError) -> Void)?,
|
|
154
151
|
options: GeolocationOptions?
|
|
155
152
|
) {
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
error?(self.createError(code: self.PERMISSION_DENIED, message: message))
|
|
169
|
-
return
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
if !CLLocationManager.locationServicesEnabled() {
|
|
173
|
-
error?(
|
|
174
|
-
self.createError(
|
|
175
|
-
code: self.POSITION_UNAVAILABLE, message: "Location services disabled."))
|
|
176
|
-
return
|
|
177
|
-
}
|
|
153
|
+
let parsedOptions = ParsedOptions.parse(from: options)
|
|
154
|
+
|
|
155
|
+
// Check authorization
|
|
156
|
+
let status = CLLocationManager.authorizationStatus()
|
|
157
|
+
if status == .denied || status == .restricted {
|
|
158
|
+
let message =
|
|
159
|
+
status == .restricted
|
|
160
|
+
? "This application is not authorized to use location services"
|
|
161
|
+
: "User denied access to location services."
|
|
162
|
+
error?(createError(code: PERMISSION_DENIED, message: message))
|
|
163
|
+
return
|
|
164
|
+
}
|
|
178
165
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
success(self.locationToPosition(cached))
|
|
184
|
-
return
|
|
185
|
-
}
|
|
166
|
+
if !CLLocationManager.locationServicesEnabled() {
|
|
167
|
+
error?(createError(code: POSITION_UNAVAILABLE, message: "Location services disabled."))
|
|
168
|
+
return
|
|
169
|
+
}
|
|
186
170
|
|
|
187
|
-
|
|
171
|
+
initializeLocationManagerIfNeeded()
|
|
188
172
|
|
|
189
|
-
|
|
190
|
-
|
|
173
|
+
// Configure location manager
|
|
174
|
+
locationManager?.desiredAccuracy = parsedOptions.accuracy
|
|
175
|
+
locationManager?.distanceFilter = parsedOptions.distanceFilter
|
|
191
176
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
177
|
+
// Create request
|
|
178
|
+
var request = LocationRequest(
|
|
179
|
+
success: success,
|
|
180
|
+
error: error,
|
|
181
|
+
options: parsedOptions,
|
|
182
|
+
timer: nil
|
|
183
|
+
)
|
|
199
184
|
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
185
|
+
// Setup timeout with DispatchSourceTimer (no run loop needed)
|
|
186
|
+
let timer = DispatchSource.makeTimerSource(queue: .main)
|
|
187
|
+
timer.schedule(deadline: .now() + parsedOptions.timeout / 1000.0)
|
|
188
|
+
timer.setEventHandler { [weak self] in
|
|
189
|
+
self?.handleTimeout(for: request.id)
|
|
190
|
+
}
|
|
191
|
+
timer.resume()
|
|
192
|
+
request.timer = timer
|
|
207
193
|
|
|
208
|
-
|
|
194
|
+
pendingRequests.append(request)
|
|
209
195
|
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
}
|
|
196
|
+
// Start location updates
|
|
197
|
+
startMonitoring()
|
|
213
198
|
}
|
|
214
199
|
|
|
215
200
|
// MARK: - Watch Position
|
|
@@ -219,56 +204,44 @@ class LocationManager: NSObject, CLLocationManagerDelegate {
|
|
|
219
204
|
error: ((GeolocationError) -> Void)?,
|
|
220
205
|
options: GeolocationOptions?
|
|
221
206
|
) -> Double {
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
207
|
+
let parsedOptions = ParsedOptions.parse(from: options)
|
|
208
|
+
let watchId = nextWatchId
|
|
209
|
+
nextWatchId += 1
|
|
210
|
+
|
|
211
|
+
let subscription = WatchSubscription(
|
|
212
|
+
success: success,
|
|
213
|
+
error: error,
|
|
214
|
+
options: parsedOptions
|
|
215
|
+
)
|
|
230
216
|
|
|
231
|
-
|
|
232
|
-
success: success,
|
|
233
|
-
error: error,
|
|
234
|
-
options: parsedOptions
|
|
235
|
-
)
|
|
217
|
+
activeWatches[watchId] = subscription
|
|
236
218
|
|
|
237
|
-
|
|
219
|
+
initializeLocationManagerIfNeeded()
|
|
238
220
|
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
221
|
+
// Configure location manager
|
|
222
|
+
locationManager?.desiredAccuracy = parsedOptions.accuracy
|
|
223
|
+
locationManager?.distanceFilter = parsedOptions.distanceFilter
|
|
242
224
|
|
|
243
|
-
|
|
244
|
-
}
|
|
225
|
+
startMonitoring()
|
|
245
226
|
|
|
246
|
-
return
|
|
227
|
+
return watchId
|
|
247
228
|
}
|
|
248
229
|
|
|
249
230
|
func clearWatch(watchId: Double) {
|
|
250
|
-
|
|
251
|
-
guard let self = self else { return }
|
|
252
|
-
|
|
253
|
-
self.activeWatches.removeValue(forKey: watchId)
|
|
231
|
+
activeWatches.removeValue(forKey: watchId)
|
|
254
232
|
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
}
|
|
233
|
+
// Stop monitoring if no more watches or pending requests
|
|
234
|
+
if activeWatches.isEmpty && pendingRequests.isEmpty {
|
|
235
|
+
stopMonitoring()
|
|
259
236
|
}
|
|
260
237
|
}
|
|
261
238
|
|
|
262
239
|
func stopObserving() {
|
|
263
|
-
|
|
264
|
-
guard let self = self else { return }
|
|
240
|
+
activeWatches.removeAll()
|
|
265
241
|
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
if self.pendingRequests.isEmpty {
|
|
270
|
-
self.stopMonitoring()
|
|
271
|
-
}
|
|
242
|
+
// Stop monitoring if no pending requests
|
|
243
|
+
if pendingRequests.isEmpty {
|
|
244
|
+
stopMonitoring()
|
|
272
245
|
}
|
|
273
246
|
}
|
|
274
247
|
|
|
@@ -298,7 +271,7 @@ class LocationManager: NSObject, CLLocationManagerDelegate {
|
|
|
298
271
|
|
|
299
272
|
// 1. Fire all pending getCurrentPosition requests
|
|
300
273
|
for request in pendingRequests {
|
|
301
|
-
request.timer?.
|
|
274
|
+
request.timer?.cancel()
|
|
302
275
|
request.success(position)
|
|
303
276
|
}
|
|
304
277
|
pendingRequests.removeAll()
|
|
@@ -338,7 +311,7 @@ class LocationManager: NSObject, CLLocationManagerDelegate {
|
|
|
338
311
|
|
|
339
312
|
// Fire all pending requests with error
|
|
340
313
|
for request in pendingRequests {
|
|
341
|
-
request.timer?.
|
|
314
|
+
request.timer?.cancel()
|
|
342
315
|
request.error?(geoError)
|
|
343
316
|
}
|
|
344
317
|
pendingRequests.removeAll()
|
|
@@ -355,8 +328,17 @@ class LocationManager: NSObject, CLLocationManagerDelegate {
|
|
|
355
328
|
|
|
356
329
|
private func initializeLocationManagerIfNeeded() {
|
|
357
330
|
guard locationManager == nil else { return }
|
|
358
|
-
|
|
359
|
-
|
|
331
|
+
|
|
332
|
+
// CLLocationManager must be created on main thread for delegate callbacks
|
|
333
|
+
if Thread.isMainThread {
|
|
334
|
+
locationManager = CLLocationManager()
|
|
335
|
+
locationManager?.delegate = self
|
|
336
|
+
} else {
|
|
337
|
+
DispatchQueue.main.sync {
|
|
338
|
+
locationManager = CLLocationManager()
|
|
339
|
+
locationManager?.delegate = self
|
|
340
|
+
}
|
|
341
|
+
}
|
|
360
342
|
}
|
|
361
343
|
|
|
362
344
|
private func updateLocationManagerConfiguration() {
|
|
@@ -408,7 +390,7 @@ class LocationManager: NSObject, CLLocationManagerDelegate {
|
|
|
408
390
|
}
|
|
409
391
|
}
|
|
410
392
|
|
|
411
|
-
|
|
393
|
+
func isCachedLocationValid(_ location: CLLocation, options: ParsedOptions) -> Bool {
|
|
412
394
|
// Check if maximumAge is infinity
|
|
413
395
|
if options.maximumAge.isInfinite {
|
|
414
396
|
return true
|
|
@@ -428,13 +410,16 @@ class LocationManager: NSObject, CLLocationManagerDelegate {
|
|
|
428
410
|
return true
|
|
429
411
|
}
|
|
430
412
|
|
|
431
|
-
private func handleTimeout(for
|
|
432
|
-
// Find and remove the request with this
|
|
433
|
-
if let index = pendingRequests.firstIndex(where: { $0.
|
|
413
|
+
private func handleTimeout(for requestId: UUID) {
|
|
414
|
+
// Find and remove the request with this ID
|
|
415
|
+
if let index = pendingRequests.firstIndex(where: { $0.id == requestId }) {
|
|
434
416
|
let request = pendingRequests[index]
|
|
435
417
|
pendingRequests.remove(at: index)
|
|
436
418
|
|
|
437
|
-
//
|
|
419
|
+
// Cancel timer
|
|
420
|
+
request.timer?.cancel()
|
|
421
|
+
|
|
422
|
+
// Return timeout error
|
|
438
423
|
let timeoutSeconds = request.options.timeout / 1000.0
|
|
439
424
|
let message = String(format: "Unable to fetch location within %.1fs.", timeoutSeconds)
|
|
440
425
|
request.error?(createError(code: TIMEOUT, message: message))
|
|
@@ -493,7 +478,7 @@ class LocationManager: NSObject, CLLocationManagerDelegate {
|
|
|
493
478
|
queuedAuthorizationCallbacks.removeAll()
|
|
494
479
|
}
|
|
495
480
|
|
|
496
|
-
|
|
481
|
+
func locationToPosition(_ location: CLLocation) -> GeolocationResponse {
|
|
497
482
|
let altitude = location.verticalAccuracy < 0 ? 0.0 : location.altitude
|
|
498
483
|
let altitudeAccuracy = location.verticalAccuracy < 0 ? 0.0 : location.verticalAccuracy
|
|
499
484
|
let heading = location.course >= 0 ? location.course : -1.0
|
|
@@ -502,11 +487,11 @@ class LocationManager: NSObject, CLLocationManagerDelegate {
|
|
|
502
487
|
let coordsObj = GeolocationCoordinates(
|
|
503
488
|
latitude: location.coordinate.latitude,
|
|
504
489
|
longitude: location.coordinate.longitude,
|
|
505
|
-
altitude: altitude,
|
|
490
|
+
altitude: .second(altitude),
|
|
506
491
|
accuracy: location.horizontalAccuracy,
|
|
507
|
-
altitudeAccuracy: altitudeAccuracy,
|
|
508
|
-
heading: heading,
|
|
509
|
-
speed: speed
|
|
492
|
+
altitudeAccuracy: .second(altitudeAccuracy),
|
|
493
|
+
heading: .second(heading),
|
|
494
|
+
speed: .second(speed)
|
|
510
495
|
)
|
|
511
496
|
|
|
512
497
|
let position = GeolocationResponse(
|