diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index e136e20..41acf61 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -20,6 +20,7 @@
+
diff --git a/ios/Podfile.lock b/ios/Podfile.lock
index 1cedc3b..555b43a 100644
--- a/ios/Podfile.lock
+++ b/ios/Podfile.lock
@@ -198,6 +198,53 @@ PODS:
- nanopb/encode (= 2.30910.0)
- nanopb/decode (2.30910.0)
- nanopb/encode (2.30910.0)
+ - NitroGeolocation (1.4.2):
+ - hermes-engine
+ - NitroModules
+ - RCTRequired
+ - RCTTypeSafety
+ - React-callinvoker
+ - React-Core
+ - React-Core-prebuilt
+ - React-debug
+ - React-Fabric
+ - React-featureflags
+ - React-graphics
+ - React-ImageManager
+ - React-jsi
+ - React-NativeModulesApple
+ - React-RCTFabric
+ - React-renderercss
+ - React-rendererdebug
+ - React-utils
+ - ReactCodegen
+ - ReactCommon/turbomodule/bridging
+ - ReactCommon/turbomodule/core
+ - ReactNativeDependencies
+ - Yoga
+ - NitroModules (0.36.1):
+ - hermes-engine
+ - RCTRequired
+ - RCTTypeSafety
+ - React-callinvoker
+ - React-Core
+ - React-Core-prebuilt
+ - React-debug
+ - React-Fabric
+ - React-featureflags
+ - React-graphics
+ - React-ImageManager
+ - React-jsi
+ - React-NativeModulesApple
+ - React-RCTFabric
+ - React-renderercss
+ - React-rendererdebug
+ - React-utils
+ - ReactCodegen
+ - ReactCommon/turbomodule/bridging
+ - ReactCommon/turbomodule/core
+ - ReactNativeDependencies
+ - Yoga
- op-sqlite (15.2.5):
- hermes-engine
- OpenSSL-Universal
@@ -1714,28 +1761,6 @@ PODS:
- Yoga
- react-native-geocoder (0.5.0):
- React
- - react-native-geolocation (3.4.0):
- - hermes-engine
- - RCTRequired
- - RCTTypeSafety
- - React-Core
- - React-Core-prebuilt
- - React-debug
- - React-Fabric
- - React-featureflags
- - React-graphics
- - React-ImageManager
- - React-jsi
- - React-NativeModulesApple
- - React-RCTFabric
- - React-renderercss
- - React-rendererdebug
- - React-utils
- - ReactCodegen
- - ReactCommon/turbomodule/bridging
- - ReactCommon/turbomodule/core
- - ReactNativeDependencies
- - Yoga
- react-native-google-maps (1.20.1):
- Google-Maps-iOS-Utils (= 5.0.0)
- GoogleMaps (= 8.4.0)
@@ -2923,6 +2948,8 @@ DEPENDENCIES:
- IQKeyboardManager
- MendixNative (from `../node_modules/mendix-native`)
- nanopb
+ - NitroGeolocation (from `../node_modules/react-native-nitro-geolocation`)
+ - NitroModules (from `../node_modules/react-native-nitro-modules`)
- "op-sqlite (from `../node_modules/@op-engineering/op-sqlite`)"
- QRCodeReader.swift (~> 10.1.0)
- RCTDeprecation (from `../node_modules/react-native/ReactApple/Libraries/RCTFoundation/RCTDeprecation`)
@@ -2967,7 +2994,6 @@ DEPENDENCIES:
- "react-native-cameraroll (from `../node_modules/@react-native-camera-roll/camera-roll`)"
- react-native-file-viewer-turbo (from `../node_modules/react-native-file-viewer-turbo`)
- react-native-geocoder (from `../node_modules/react-native-geocoder`)
- - "react-native-geolocation (from `../node_modules/@react-native-community/geolocation`)"
- react-native-google-maps (from `../node_modules/react-native-maps`)
- react-native-image-picker (from `../node_modules/react-native-image-picker`)
- react-native-maps (from `../node_modules/react-native-maps`)
@@ -3082,6 +3108,10 @@ EXTERNAL SOURCES:
:tag: hermes-v250829098.0.9
MendixNative:
:path: "../node_modules/mendix-native"
+ NitroGeolocation:
+ :path: "../node_modules/react-native-nitro-geolocation"
+ NitroModules:
+ :path: "../node_modules/react-native-nitro-modules"
op-sqlite:
:path: "../node_modules/@op-engineering/op-sqlite"
RCTDeprecation:
@@ -3166,8 +3196,6 @@ EXTERNAL SOURCES:
:path: "../node_modules/react-native-file-viewer-turbo"
react-native-geocoder:
:path: "../node_modules/react-native-geocoder"
- react-native-geolocation:
- :path: "../node_modules/@react-native-community/geolocation"
react-native-google-maps:
:path: "../node_modules/react-native-maps"
react-native-image-picker:
@@ -3331,12 +3359,14 @@ SPEC CHECKSUMS:
GoogleDataTransport: 6c09b596d841063d76d4288cc2d2f42cc36e1e2a
GoogleMaps: 8939898920281c649150e0af74aa291c60f2e77d
GoogleUtilities: ea963c370a38a8069cc5f7ba4ca849a60b6d7d15
- hermes-engine: 48a4081d5ebf9ec3b0d6ad6a11254f1f5a7f5bae
+ hermes-engine: 166613ab57f3dde1bf3f24c60212b66a1d585f8b
IQKeyboardManager: c8665b3396bd0b79402b4c573eac345a31c7d485
libwebp: 02b23773aedb6ff1fd38cec7a77b81414c6842a8
MendixNative: 7cba944a4e608e6ab40ec281e9b2b0f9f3cdefe0
MultiplatformBleAdapter: b1fddd0d499b96b607e00f0faa8e60648343dc1d
nanopb: 438bc412db1928dac798aa6fd75726007be04262
+ NitroGeolocation: 647199e12e95fa2e4030e872ede9a3598fd379d3
+ NitroModules: 4d19ff59969b2c67a19175fb17b66917af6708e0
op-sqlite: e9ef65bcf95a97863874cee87841425bb71c8396
OpenSSL-Universal: 9110d21982bb7e8b22a962b6db56a8aa805afde7
PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47
@@ -3350,7 +3380,7 @@ SPEC CHECKSUMS:
React: 1ba7d364ade7d883a1ec055bfc3606f35fdee17b
React-callinvoker: bc2a26f8d84fb01f003fc6de6c9337b64715f95b
React-Core: 7840d3a80b43a95c5e80ef75146bd70925ebab0f
- React-Core-prebuilt: da3a158f1e31b83bdf28f7855e22a0885cfb9d61
+ React-Core-prebuilt: 2439654d53489a5609231fe950d7f4e4c641ad52
React-CoreModules: 2eb010400b63b89e53a324ffb3c112e4c7c3ce42
React-cxxreact: a558e92199d26f145afa9e62c4233cf8e7950efe
React-debug: 755200a6e7f5e6e0a40ff8d215493d43cce285fc
@@ -3383,7 +3413,6 @@ SPEC CHECKSUMS:
react-native-cameraroll: bd1a177463acbba89365d09e81057294eba1e2f6
react-native-file-viewer-turbo: 0da5fe2575b1c2e43ce8246fcd0fa9c3b097a72d
react-native-geocoder: bc977303c9c53cce36bcdb3c6f17e6832f86beb6
- react-native-geolocation: cfc39041210bd9f591ec2beb7d417291251da8e5
react-native-google-maps: c4f5c5b2dda17e7cb2cb2b37a81f140b039b3e7e
react-native-image-picker: 168d6972e50ea848defe4ac4c222faa9bc52aea0
react-native-maps: 9febd31278b35cd21e4fad2cf6fa708993be5dab
@@ -3430,7 +3459,7 @@ SPEC CHECKSUMS:
ReactCodegen: 797de5178718324c6eba3327b07f9a423fbd5787
ReactCommon: 07572bf9e687c8a52fbe4a3641e9e3a1a477c78e
ReactNativeBiometrics: 9ead8d633833fd13e5a79564af8ba7064c2a58c6
- ReactNativeDependencies: b2c3c0cdbf1823de4ac83c51bf6e64ee0ecd86ad
+ ReactNativeDependencies: 14132e559d3008cd261e3c00859a58fd4f7fa42c
RNBootSplash: 13b7612788960d0c5446e68489ac2509e506cfcd
RNCalendarEvents: f90f73666b6bcbb3cc8a491ffbb5e48c0db3de37
RNCAsyncStorage: 3a4f5e2777dae1688b781a487923a08569e27fe4
@@ -3461,6 +3490,6 @@ SPEC CHECKSUMS:
VisionCamera: 7187b3dac1ff3071234ead959ce311875748e14f
Yoga: c0b3f2c7e8d3e327e450223a2414ca3fa296b9a2
-PODFILE CHECKSUM: 82c9cfbd7db4666e2b937d7c62e7ff7cd5466d02
+PODFILE CHECKSUM: 3ac57498e7a5b50e63c45224f2a40431ea916f8c
COCOAPODS: 1.16.2
diff --git a/package-lock.json b/package-lock.json
index 6c7c0cd..37290e2 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -20,7 +20,6 @@
"@react-native-community/cli-platform-android": "20.1.3",
"@react-native-community/cli-platform-ios": "20.1.3",
"@react-native-community/datetimepicker": "8.6.0",
- "@react-native-community/geolocation": "3.4.0",
"@react-native-community/netinfo": "11.5.2",
"@react-native-firebase/analytics": "20.1.0",
"@react-native-firebase/app": "20.1.0",
@@ -51,6 +50,8 @@
"react-native-linear-gradient": "2.8.3",
"react-native-localize": "3.7.0",
"react-native-maps": "1.20.1",
+ "react-native-nitro-geolocation": "1.4.2",
+ "react-native-nitro-modules": "0.36.1",
"react-native-pager-view": "6.9.1",
"react-native-permissions": "5.5.1",
"react-native-reanimated": "4.3.1",
@@ -2273,19 +2274,6 @@
}
}
},
- "node_modules/@react-native-community/geolocation": {
- "version": "3.4.0",
- "resolved": "https://registry.npmjs.org/@react-native-community/geolocation/-/geolocation-3.4.0.tgz",
- "integrity": "sha512-bzZH89/cwmpkPMKKveoC72C4JH0yF4St5Ceg/ZM9pA1SqX9MlRIrIrrOGZ/+yi++xAvFDiYfihtn9TvXWU9/rA==",
- "license": "MIT",
- "engines": {
- "node": ">=18.0.0"
- },
- "peerDependencies": {
- "react": "*",
- "react-native": "*"
- }
- },
"node_modules/@react-native-community/netinfo": {
"version": "11.5.2",
"resolved": "https://registry.npmjs.org/@react-native-community/netinfo/-/netinfo-11.5.2.tgz",
@@ -8029,6 +8017,27 @@
}
}
},
+ "node_modules/react-native-nitro-geolocation": {
+ "version": "1.4.2",
+ "resolved": "https://registry.npmjs.org/react-native-nitro-geolocation/-/react-native-nitro-geolocation-1.4.2.tgz",
+ "integrity": "sha512-woUfdQgzWeTFrluUkfLyHIAPCJFCX00BPWDC+1w6c0eLkkr9SNFX0UFANdEP5aOBw+LGhb4utH/LmeVl3X3MmQ==",
+ "license": "MIT",
+ "peerDependencies": {
+ "react": ">=18.0.0",
+ "react-native": ">=0.75.0",
+ "react-native-nitro-modules": "*"
+ }
+ },
+ "node_modules/react-native-nitro-modules": {
+ "version": "0.36.1",
+ "resolved": "https://registry.npmjs.org/react-native-nitro-modules/-/react-native-nitro-modules-0.36.1.tgz",
+ "integrity": "sha512-kBv/VvKqAmkXAvP1DxJMC9b/fRhh7JdSO4EUnPP46hJjrIFeFR8AwKm8mYaKZEuF014M/TVdv2vomVUW0umsQQ==",
+ "license": "MIT",
+ "peerDependencies": {
+ "react": "*",
+ "react-native": "*"
+ }
+ },
"node_modules/react-native-pager-view": {
"version": "6.9.1",
"resolved": "https://registry.npmjs.org/react-native-pager-view/-/react-native-pager-view-6.9.1.tgz",
diff --git a/package.json b/package.json
index 6ab0b95..5f18d6f 100644
--- a/package.json
+++ b/package.json
@@ -31,7 +31,6 @@
"@react-native-community/cli-platform-android": "20.1.3",
"@react-native-community/cli-platform-ios": "20.1.3",
"@react-native-community/datetimepicker": "8.6.0",
- "@react-native-community/geolocation": "3.4.0",
"@react-native-community/netinfo": "11.5.2",
"@react-native-firebase/analytics": "20.1.0",
"@react-native-firebase/app": "20.1.0",
@@ -50,6 +49,8 @@
"react-native-fast-image": "8.6.3",
"react-native-file-viewer-turbo": "0.7.4",
"react-native-geocoder": "0.5.0",
+ "react-native-nitro-geolocation": "1.4.2",
+ "react-native-nitro-modules": "0.36.1",
"react-native-gesture-handler": "2.31.2",
"react-native-image-picker": "7.2.3",
"react-native-inappbrowser-reborn": "3.7.0",
diff --git a/patches/react-native-nitro-geolocation+1.4.2.patch b/patches/react-native-nitro-geolocation+1.4.2.patch
new file mode 100644
index 0000000..ad03173
--- /dev/null
+++ b/patches/react-native-nitro-geolocation+1.4.2.patch
@@ -0,0 +1,315 @@
+diff --git a/node_modules/react-native-nitro-geolocation/android/src/main/java/com/margelo/nitro/nitrogeolocation/GetCurrentPosition.kt b/node_modules/react-native-nitro-geolocation/android/src/main/java/com/margelo/nitro/nitrogeolocation/GetCurrentPosition.kt
+index e3124f0..527e0bb 100644
+--- a/node_modules/react-native-nitro-geolocation/android/src/main/java/com/margelo/nitro/nitrogeolocation/GetCurrentPosition.kt
++++ b/node_modules/react-native-nitro-geolocation/android/src/main/java/com/margelo/nitro/nitrogeolocation/GetCurrentPosition.kt
+@@ -12,6 +12,15 @@ import android.os.Looper
+ import android.util.Log
+ import androidx.core.content.ContextCompat
+ import com.facebook.react.bridge.ReactApplicationContext
++import com.google.android.gms.common.ConnectionResult
++import com.google.android.gms.common.GoogleApiAvailability
++import com.google.android.gms.location.FusedLocationProviderClient
++import com.google.android.gms.location.LocationCallback
++import com.google.android.gms.location.LocationRequest
++import com.google.android.gms.location.LocationResult
++import com.google.android.gms.location.LocationServices
++import com.google.android.gms.location.Priority
++import com.google.android.gms.location.LocationAvailability
+
+ class GetCurrentPosition(private val reactContext: ReactApplicationContext) {
+
+@@ -19,6 +28,121 @@ class GetCurrentPosition(private val reactContext: ReactApplicationContext) {
+ success: (position: CompatGeolocationResponse) -> Unit,
+ error: ((error: CompatGeolocationError) -> Unit)?,
+ options: CompatGeolocationOptions?
++ ) {
++ val opts = parseOptions(options)
++
++ // Use FusedLocationProviderClient when Play Services are available
++ if (isGooglePlayServicesAvailable()) {
++ getCurrentPositionWithFused(success, error, opts)
++ return
++ }
++
++ // Fallback to basic LocationManager
++ getCurrentPositionWithLocationManager(success, error, opts)
++ }
++
++ // ===== Fused Location Provider (Play Services) Path =====
++
++ private fun getCurrentPositionWithFused(
++ success: (CompatGeolocationResponse) -> Unit,
++ error: ((CompatGeolocationError) -> Unit)?,
++ options: ParsedOptions
++ ) {
++ val fusedLocationClient = LocationServices.getFusedLocationProviderClient(reactContext)
++
++ try {
++ fusedLocationClient.lastLocation
++ .addOnSuccessListener { location ->
++ if (location != null && isCachedLocationValid(location, options)) {
++ success(locationToPosition(location))
++ } else {
++ requestFreshFusedLocation(fusedLocationClient, success, error, options)
++ }
++ }
++ .addOnFailureListener {
++ requestFreshFusedLocation(fusedLocationClient, success, error, options)
++ }
++ } catch (e: SecurityException) {
++ Log.e(TAG, "Security exception: ${e.message}")
++ error?.invoke(
++ createError(PERMISSION_DENIED, "Location permission denied: ${e.message}")
++ )
++ }
++ }
++
++ private fun requestFreshFusedLocation(
++ fusedLocationClient: FusedLocationProviderClient,
++ success: (CompatGeolocationResponse) -> Unit,
++ error: ((CompatGeolocationError) -> Unit)?,
++ options: ParsedOptions
++ ) {
++ val handler = Handler(Looper.getMainLooper())
++ var isResolved = false
++
++ val locationRequest = LocationRequest.Builder(0)
++ .setPriority(
++ if (options.androidAccuracy.mode == AndroidAccuracyMode.HIGH)
++ Priority.PRIORITY_HIGH_ACCURACY
++ else
++ Priority.PRIORITY_BALANCED_POWER_ACCURACY
++ )
++ .setMaxUpdateAgeMillis(options.maximumAge.toLong().coerceAtLeast(0L))
++ .setMinUpdateDistanceMeters(0f)
++ .setMaxUpdates(1)
++ .build()
++
++ val locationCallback = object : LocationCallback() {
++ override fun onLocationResult(locationResult: LocationResult) {
++ val location = locationResult.lastLocation
++
++ if (location == null) {
++ // Don't error on null location - wait for timeout or next callback
++ return
++ }
++
++ if (!isResolved) {
++ isResolved = true
++ handler.removeCallbacksAndMessages(null)
++ fusedLocationClient.removeLocationUpdates(this)
++ success(locationToPosition(location))
++ }
++ }
++
++ override fun onLocationAvailability(locationAvailability: LocationAvailability) {
++ if (!locationAvailability.isLocationAvailable) {
++ // Don't error immediately - wait for timeout or a location update
++ return
++ }
++ }
++ }
++
++ val timeoutRunnable = Runnable {
++ if (!isResolved) {
++ isResolved = true
++ fusedLocationClient.removeLocationUpdates(locationCallback)
++ error?.invoke(createError(TIMEOUT, "Location request timed out"))
++ }
++ }
++
++ try {
++ fusedLocationClient.requestLocationUpdates(
++ locationRequest,
++ locationCallback,
++ Looper.getMainLooper()
++ )
++ handler.postDelayed(timeoutRunnable, options.timeout.toLong())
++ } catch (e: SecurityException) {
++ Log.e(TAG, "SecurityException in fused request: ${e.message}")
++ error?.invoke(createError(PERMISSION_DENIED, "Permission denied: ${e.message}"))
++ }
++ }
++
++ // ===== Basic LocationManager Path (Fallback) =====
++
++ private fun getCurrentPositionWithLocationManager(
++ success: (CompatGeolocationResponse) -> Unit,
++ error: ((CompatGeolocationError) -> Unit)?,
++ options: ParsedOptions
+ ) {
+ val locationManager =
+ reactContext.getSystemService(Context.LOCATION_SERVICE) as? LocationManager
+@@ -28,8 +152,7 @@ class GetCurrentPosition(private val reactContext: ReactApplicationContext) {
+ return
+ }
+
+- val opts = parseOptions(options)
+- val provider = getValidProvider(locationManager, opts.androidAccuracy)
++ val provider = getValidProvider(locationManager, options.androidAccuracy)
+
+ if (provider == null) {
+ Log.e(TAG, "No location provider available")
+@@ -41,19 +164,19 @@ class GetCurrentPosition(private val reactContext: ReactApplicationContext) {
+ val lastKnownLocation = locationManager.getLastKnownLocation(provider)
+
+ // Check if cached location is fresh enough
+- if (lastKnownLocation != null && isCachedLocationValid(lastKnownLocation, opts)) {
++ if (lastKnownLocation != null && isCachedLocationValid(lastKnownLocation, options)) {
+ success(locationToPosition(lastKnownLocation))
+ return
+ }
+
+ // If maximumAge is Infinity and we have a last known location, use it
+- if (lastKnownLocation != null && opts.maximumAge == Double.POSITIVE_INFINITY) {
++ if (lastKnownLocation != null && options.maximumAge == Double.POSITIVE_INFINITY) {
+ success(locationToPosition(lastKnownLocation))
+ return
+ }
+
+ // Request fresh location
+- requestFreshLocation(locationManager, provider, opts, success, error, lastKnownLocation)
++ requestFreshLocation(locationManager, provider, options, success, error, lastKnownLocation)
+ } catch (e: SecurityException) {
+ Log.e(TAG, "Security exception: ${e.message}")
+ error?.invoke(
+@@ -64,6 +187,11 @@ class GetCurrentPosition(private val reactContext: ReactApplicationContext) {
+
+ // ===== Helper Functions =====
+
++ private fun isGooglePlayServicesAvailable(): Boolean {
++ return GoogleApiAvailability.getInstance()
++ .isGooglePlayServicesAvailable(reactContext.applicationContext) == ConnectionResult.SUCCESS
++ }
++
+ private fun parseOptions(options: CompatGeolocationOptions?): ParsedOptions {
+ return ParsedOptions(
+ timeout = options?.timeout ?: DEFAULT_TIMEOUT,
+diff --git a/node_modules/react-native-nitro-geolocation/android/src/main/java/com/margelo/nitro/nitrogeolocation/WatchPosition.kt b/node_modules/react-native-nitro-geolocation/android/src/main/java/com/margelo/nitro/nitrogeolocation/WatchPosition.kt
+index e0cbe24..4f29d39 100644
+--- a/node_modules/react-native-nitro-geolocation/android/src/main/java/com/margelo/nitro/nitrogeolocation/WatchPosition.kt
++++ b/node_modules/react-native-nitro-geolocation/android/src/main/java/com/margelo/nitro/nitrogeolocation/WatchPosition.kt
+@@ -11,6 +11,14 @@ import android.os.Looper
+ import android.util.Log
+ import androidx.core.content.ContextCompat
+ import com.facebook.react.bridge.ReactApplicationContext
++import com.google.android.gms.common.ConnectionResult
++import com.google.android.gms.common.GoogleApiAvailability
++import com.google.android.gms.location.FusedLocationProviderClient
++import com.google.android.gms.location.LocationCallback
++import com.google.android.gms.location.LocationRequest
++import com.google.android.gms.location.LocationResult
++import com.google.android.gms.location.LocationServices
++import com.google.android.gms.location.Priority
+ import java.util.concurrent.ConcurrentHashMap
+ import java.util.concurrent.atomic.AtomicInteger
+
+@@ -19,8 +27,11 @@ class WatchPosition(private val reactContext: ReactApplicationContext) {
+ private val watchCallbacks = ConcurrentHashMap()
+ private val watchIdGenerator = AtomicInteger(0)
+ private var locationListener: LocationListener? = null
++ private var fusedLocationCallback: LocationCallback? = null
++ private var fusedLocationClient: FusedLocationProviderClient? = null
+ private var watchedProvider: String? = null
+ private var currentOptions: CompatGeolocationOptions? = null
++ private var usingFusedProvider = false
+
+ data class WatchCallback(
+ val success: (CompatGeolocationResponse) -> Unit,
+@@ -54,18 +65,80 @@ class WatchPosition(private val reactContext: ReactApplicationContext) {
+ }
+
+ fun stopObserving() {
+- val locationManager =
+- reactContext.getSystemService(Context.LOCATION_SERVICE) as? LocationManager
+-
+- locationListener?.let { listener -> locationManager?.removeUpdates(listener) }
++ if (usingFusedProvider) {
++ fusedLocationCallback?.let { callback ->
++ fusedLocationClient?.removeLocationUpdates(callback)
++ }
++ fusedLocationCallback = null
++ fusedLocationClient = null
++ } else {
++ val locationManager =
++ reactContext.getSystemService(Context.LOCATION_SERVICE) as? LocationManager
++ locationListener?.let { listener -> locationManager?.removeUpdates(listener) }
++ }
+
+ locationListener = null
+ watchedProvider = null
+ currentOptions = null
++ usingFusedProvider = false
+ watchCallbacks.clear()
+ }
+
+ private fun startObserving(options: CompatGeolocationOptions?) {
++ // Use FusedLocationProviderClient when Play Services are available
++ if (isGooglePlayServicesAvailable()) {
++ startObservingWithFused(options)
++ return
++ }
++
++ // Fallback to basic LocationManager
++ startObservingWithLocationManager(options)
++ }
++
++ private fun startObservingWithFused(options: CompatGeolocationOptions?) {
++ val opts = parseOptions(options)
++ val client = LocationServices.getFusedLocationProviderClient(reactContext)
++
++ val locationRequest = LocationRequest.Builder(
++ if (opts.androidAccuracy.mode == AndroidAccuracyMode.HIGH)
++ Priority.PRIORITY_HIGH_ACCURACY
++ else
++ Priority.PRIORITY_BALANCED_POWER_ACCURACY,
++ opts.interval.toLong()
++ )
++ .setMinUpdateDistanceMeters(opts.distanceFilter.toFloat())
++ .build()
++
++ val callback = object : LocationCallback() {
++ override fun onLocationResult(locationResult: LocationResult) {
++ val location = locationResult.lastLocation ?: return
++ val position = locationToPosition(location)
++ watchCallbacks.values.forEach { watchCallback -> watchCallback.success(position) }
++ }
++ }
++
++ try {
++ client.requestLocationUpdates(
++ locationRequest,
++ callback,
++ Looper.getMainLooper()
++ )
++ fusedLocationClient = client
++ fusedLocationCallback = callback
++ usingFusedProvider = true
++ currentOptions = options
++ } catch (e: SecurityException) {
++ Log.e(TAG, "SecurityException: ${e.message}")
++ emitErrorToAll(
++ createError(
++ GetCurrentPosition.PERMISSION_DENIED,
++ "Location permission denied: ${e.message}"
++ )
++ )
++ }
++ }
++
++ private fun startObservingWithLocationManager(options: CompatGeolocationOptions?) {
+ val locationManager =
+ reactContext.getSystemService(Context.LOCATION_SERVICE) as? LocationManager
+
+@@ -143,6 +216,11 @@ class WatchPosition(private val reactContext: ReactApplicationContext) {
+ }
+ }
+
++ private fun isGooglePlayServicesAvailable(): Boolean {
++ return GoogleApiAvailability.getInstance()
++ .isGooglePlayServicesAvailable(reactContext.applicationContext) == ConnectionResult.SUCCESS
++ }
++
+ private fun emitErrorToAll(error: CompatGeolocationError) {
+ watchCallbacks.values.forEach { callback -> callback.error?.invoke(error) }
+ }