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,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Represents a location request with its configuration options.
|
|
3
|
+
*/
|
|
4
|
+
export interface LocationRequest {
|
|
5
|
+
/** Whether high accuracy mode is enabled */
|
|
6
|
+
enableHighAccuracy: boolean;
|
|
7
|
+
/** Minimum distance change (in meters) for updates */
|
|
8
|
+
distanceFilter: number;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Accuracy level for location services.
|
|
13
|
+
* - 'high': GPS-level accuracy (~5-10 meters)
|
|
14
|
+
* - 'medium': Network-assisted accuracy (~100 meters)
|
|
15
|
+
* - 'low': Cell tower accuracy (~1000+ meters)
|
|
16
|
+
*/
|
|
17
|
+
export type AccuracyLevel = "high" | "medium" | "low";
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Merged configuration representing the optimal settings
|
|
21
|
+
* for multiple concurrent location requests.
|
|
22
|
+
*/
|
|
23
|
+
export interface MergedConfiguration {
|
|
24
|
+
/** The best (highest) accuracy level among all requests */
|
|
25
|
+
bestAccuracy: AccuracyLevel;
|
|
26
|
+
/** The smallest (most sensitive) distance filter among all requests */
|
|
27
|
+
smallestDistanceFilter: number;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Merges multiple location request configurations to determine
|
|
32
|
+
* the optimal settings that satisfy all requests.
|
|
33
|
+
*
|
|
34
|
+
* This is important for battery optimization - when multiple watches
|
|
35
|
+
* or getCurrentPosition calls are active simultaneously, we should use
|
|
36
|
+
* the most demanding settings to satisfy all requests with a single
|
|
37
|
+
* location subscription.
|
|
38
|
+
*
|
|
39
|
+
* Strategy:
|
|
40
|
+
* - Use the highest accuracy level requested by any client
|
|
41
|
+
* - Use the smallest distance filter to ensure all clients get updates
|
|
42
|
+
*
|
|
43
|
+
* @param requests - Array of location requests to merge
|
|
44
|
+
* @returns Merged configuration with optimal settings
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* ```ts
|
|
48
|
+
* const requests = [
|
|
49
|
+
* { enableHighAccuracy: false, distanceFilter: 100 },
|
|
50
|
+
* { enableHighAccuracy: true, distanceFilter: 10 },
|
|
51
|
+
* { enableHighAccuracy: false, distanceFilter: 50 }
|
|
52
|
+
* ];
|
|
53
|
+
*
|
|
54
|
+
* const merged = mergeConfigurations(requests);
|
|
55
|
+
* // Result: { bestAccuracy: 'high', smallestDistanceFilter: 10 }
|
|
56
|
+
* ```
|
|
57
|
+
*/
|
|
58
|
+
export function mergeConfigurations(
|
|
59
|
+
requests: LocationRequest[]
|
|
60
|
+
): MergedConfiguration {
|
|
61
|
+
// If no requests, return default low-power settings
|
|
62
|
+
if (requests.length === 0) {
|
|
63
|
+
return {
|
|
64
|
+
bestAccuracy: "low",
|
|
65
|
+
smallestDistanceFilter: 0
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
let bestAccuracy: AccuracyLevel = "low";
|
|
70
|
+
let smallestDistanceFilter = Number.POSITIVE_INFINITY;
|
|
71
|
+
|
|
72
|
+
// Iterate through all requests to find the most demanding settings
|
|
73
|
+
for (const request of requests) {
|
|
74
|
+
// If any request needs high accuracy, use high accuracy
|
|
75
|
+
if (request.enableHighAccuracy) {
|
|
76
|
+
bestAccuracy = "high";
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Use the smallest distance filter
|
|
80
|
+
smallestDistanceFilter = Math.min(
|
|
81
|
+
smallestDistanceFilter,
|
|
82
|
+
request.distanceFilter
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return {
|
|
87
|
+
bestAccuracy,
|
|
88
|
+
smallestDistanceFilter:
|
|
89
|
+
smallestDistanceFilter === Number.POSITIVE_INFINITY
|
|
90
|
+
? 0
|
|
91
|
+
: smallestDistanceFilter
|
|
92
|
+
};
|
|
93
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Error codes for geolocation errors.
|
|
3
|
+
* These codes match the W3C Geolocation API specification.
|
|
4
|
+
*/
|
|
5
|
+
export enum LocationErrorCode {
|
|
6
|
+
/** User denied the request for Geolocation */
|
|
7
|
+
PERMISSION_DENIED = 1,
|
|
8
|
+
/** Location provider is unavailable */
|
|
9
|
+
POSITION_UNAVAILABLE = 2,
|
|
10
|
+
/** The request to get location timed out */
|
|
11
|
+
TIMEOUT = 3
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Geolocation error object.
|
|
16
|
+
*/
|
|
17
|
+
export interface LocationError extends Error {
|
|
18
|
+
code: LocationErrorCode;
|
|
19
|
+
message: string;
|
|
20
|
+
PERMISSION_DENIED: LocationErrorCode.PERMISSION_DENIED;
|
|
21
|
+
POSITION_UNAVAILABLE: LocationErrorCode.POSITION_UNAVAILABLE;
|
|
22
|
+
TIMEOUT: LocationErrorCode.TIMEOUT;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Creates a standardized LocationError object.
|
|
27
|
+
*
|
|
28
|
+
* @param code - The error code from LocationErrorCode enum
|
|
29
|
+
* @param message - A human-readable error message
|
|
30
|
+
* @returns A LocationError object
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* ```ts
|
|
34
|
+
* const error = createLocationError(
|
|
35
|
+
* LocationErrorCode.PERMISSION_DENIED,
|
|
36
|
+
* 'User denied location permission'
|
|
37
|
+
* );
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
export function createLocationError(
|
|
41
|
+
code: LocationErrorCode,
|
|
42
|
+
message: string
|
|
43
|
+
): LocationError {
|
|
44
|
+
const error = new Error(message) as LocationError;
|
|
45
|
+
error.code = code;
|
|
46
|
+
error.PERMISSION_DENIED = LocationErrorCode.PERMISSION_DENIED;
|
|
47
|
+
error.POSITION_UNAVAILABLE = LocationErrorCode.POSITION_UNAVAILABLE;
|
|
48
|
+
error.TIMEOUT = LocationErrorCode.TIMEOUT;
|
|
49
|
+
return error;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Maps iOS CLError codes to LocationErrorCode.
|
|
54
|
+
*
|
|
55
|
+
* @param clErrorCode - The iOS CLError code
|
|
56
|
+
* @returns The corresponding LocationErrorCode
|
|
57
|
+
*
|
|
58
|
+
* @see https://developer.apple.com/documentation/corelocation/clerror/code
|
|
59
|
+
*/
|
|
60
|
+
export function mapCLErrorCode(clErrorCode: number): LocationErrorCode {
|
|
61
|
+
switch (clErrorCode) {
|
|
62
|
+
case 0: // kCLErrorDenied
|
|
63
|
+
return LocationErrorCode.PERMISSION_DENIED;
|
|
64
|
+
case 1: // kCLErrorLocationUnknown
|
|
65
|
+
return LocationErrorCode.POSITION_UNAVAILABLE;
|
|
66
|
+
default:
|
|
67
|
+
return LocationErrorCode.POSITION_UNAVAILABLE;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Maps Android exception types to LocationErrorCode.
|
|
73
|
+
*
|
|
74
|
+
* @param exceptionType - The Android exception class name
|
|
75
|
+
* @returns The corresponding LocationErrorCode
|
|
76
|
+
*/
|
|
77
|
+
export function mapAndroidException(exceptionType: string): LocationErrorCode {
|
|
78
|
+
if (exceptionType === "SecurityException") {
|
|
79
|
+
return LocationErrorCode.PERMISSION_DENIED;
|
|
80
|
+
}
|
|
81
|
+
return LocationErrorCode.POSITION_UNAVAILABLE;
|
|
82
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure utility functions for geolocation operations.
|
|
3
|
+
* These functions are platform-independent and can be tested with Jest.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export { isCachedLocationValid } from "./cache";
|
|
7
|
+
export {
|
|
8
|
+
LocationErrorCode,
|
|
9
|
+
createLocationError,
|
|
10
|
+
mapCLErrorCode,
|
|
11
|
+
mapAndroidException,
|
|
12
|
+
type LocationError
|
|
13
|
+
} from "./errors";
|
|
14
|
+
export {
|
|
15
|
+
isBetterLocation,
|
|
16
|
+
type LocationQuality
|
|
17
|
+
} from "./quality";
|
|
18
|
+
export {
|
|
19
|
+
selectProvider,
|
|
20
|
+
type Provider
|
|
21
|
+
} from "./provider";
|
|
22
|
+
export {
|
|
23
|
+
mergeConfigurations,
|
|
24
|
+
type LocationRequest,
|
|
25
|
+
type AccuracyLevel,
|
|
26
|
+
type MergedConfiguration
|
|
27
|
+
} from "./config";
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Location provider types supported on Android.
|
|
3
|
+
*/
|
|
4
|
+
export type Provider = "gps" | "network" | null;
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Selects the best available location provider based on user preferences
|
|
8
|
+
* and provider availability.
|
|
9
|
+
*
|
|
10
|
+
* This function implements a fallback strategy:
|
|
11
|
+
* - If high accuracy is requested, prefer GPS, fallback to Network
|
|
12
|
+
* - If low power is preferred, prefer Network, fallback to GPS
|
|
13
|
+
*
|
|
14
|
+
* @param enableHighAccuracy - Whether high accuracy mode is requested
|
|
15
|
+
* @param gpsAvailable - Whether GPS provider is available and enabled
|
|
16
|
+
* @param networkAvailable - Whether Network provider is available and enabled
|
|
17
|
+
* @returns The selected provider, or null if no providers are available
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```ts
|
|
21
|
+
* // High accuracy mode with both providers available
|
|
22
|
+
* selectProvider(true, true, true); // 'gps'
|
|
23
|
+
*
|
|
24
|
+
* // High accuracy mode but GPS is disabled
|
|
25
|
+
* selectProvider(true, false, true); // 'network'
|
|
26
|
+
*
|
|
27
|
+
* // Low power mode with both providers available
|
|
28
|
+
* selectProvider(false, true, true); // 'network'
|
|
29
|
+
*
|
|
30
|
+
* // No providers available
|
|
31
|
+
* selectProvider(true, false, false); // null
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
export function selectProvider(
|
|
35
|
+
enableHighAccuracy: boolean,
|
|
36
|
+
gpsAvailable: boolean,
|
|
37
|
+
networkAvailable: boolean
|
|
38
|
+
): Provider {
|
|
39
|
+
// Determine preferred and fallback providers based on accuracy requirement
|
|
40
|
+
const preferredProvider = enableHighAccuracy ? "gps" : "network";
|
|
41
|
+
const fallbackProvider = enableHighAccuracy ? "network" : "gps";
|
|
42
|
+
|
|
43
|
+
// Check if preferred provider is available
|
|
44
|
+
const isPreferredAvailable =
|
|
45
|
+
preferredProvider === "gps" ? gpsAvailable : networkAvailable;
|
|
46
|
+
|
|
47
|
+
// Check if fallback provider is available
|
|
48
|
+
const isFallbackAvailable =
|
|
49
|
+
fallbackProvider === "gps" ? gpsAvailable : networkAvailable;
|
|
50
|
+
|
|
51
|
+
// Return the best available provider
|
|
52
|
+
if (isPreferredAvailable) {
|
|
53
|
+
return preferredProvider;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (isFallbackAvailable) {
|
|
57
|
+
return fallbackProvider;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Represents the quality characteristics of a location reading.
|
|
3
|
+
*/
|
|
4
|
+
export interface LocationQuality {
|
|
5
|
+
/** Timestamp in milliseconds since epoch */
|
|
6
|
+
timestampMs: number;
|
|
7
|
+
/** Horizontal accuracy in meters */
|
|
8
|
+
accuracyMeters: number;
|
|
9
|
+
/** Location provider type */
|
|
10
|
+
provider: "gps" | "network";
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/** Time threshold for considering locations significantly newer/older (2 minutes) */
|
|
14
|
+
const TWO_MINUTES_MS = 2 * 60 * 1000;
|
|
15
|
+
|
|
16
|
+
/** Accuracy threshold for considering locations significantly less accurate (200 meters) */
|
|
17
|
+
const SIGNIFICANT_ACCURACY_DIFFERENCE_METERS = 200;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Determines whether a new location is better than the current best location.
|
|
21
|
+
* This algorithm considers both recency and accuracy of location readings.
|
|
22
|
+
*
|
|
23
|
+
* Based on Android's location quality evaluation best practices:
|
|
24
|
+
* @see https://developer.android.com/develop/sensors-and-location/location/strategies#BestEstimate
|
|
25
|
+
*
|
|
26
|
+
* @param newLocation - The new location to evaluate
|
|
27
|
+
* @param currentBest - The current best location, or null if none exists
|
|
28
|
+
* @returns true if the new location is better, false otherwise
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* ```ts
|
|
32
|
+
* const newLoc: LocationQuality = {
|
|
33
|
+
* timestampMs: Date.now(),
|
|
34
|
+
* accuracyMeters: 10,
|
|
35
|
+
* provider: 'gps'
|
|
36
|
+
* };
|
|
37
|
+
*
|
|
38
|
+
* const currentBest: LocationQuality = {
|
|
39
|
+
* timestampMs: Date.now() - 60000, // 1 minute ago
|
|
40
|
+
* accuracyMeters: 50,
|
|
41
|
+
* provider: 'network'
|
|
42
|
+
* };
|
|
43
|
+
*
|
|
44
|
+
* isBetterLocation(newLoc, currentBest); // true (newer and more accurate)
|
|
45
|
+
* ```
|
|
46
|
+
*/
|
|
47
|
+
export function isBetterLocation(
|
|
48
|
+
newLocation: LocationQuality,
|
|
49
|
+
currentBest: LocationQuality | null
|
|
50
|
+
): boolean {
|
|
51
|
+
// If there's no current best location, the new location is always better
|
|
52
|
+
if (!currentBest) {
|
|
53
|
+
return true;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Calculate time difference between locations
|
|
57
|
+
const timeDelta = newLocation.timestampMs - currentBest.timestampMs;
|
|
58
|
+
const isSignificantlyNewer = timeDelta > TWO_MINUTES_MS;
|
|
59
|
+
const isSignificantlyOlder = timeDelta < -TWO_MINUTES_MS;
|
|
60
|
+
|
|
61
|
+
// If the new location is significantly newer, it's better
|
|
62
|
+
if (isSignificantlyNewer) {
|
|
63
|
+
return true;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// If the new location is significantly older, it's not better
|
|
67
|
+
if (isSignificantlyOlder) {
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Calculate accuracy difference
|
|
72
|
+
const accuracyDelta = newLocation.accuracyMeters - currentBest.accuracyMeters;
|
|
73
|
+
const isMoreAccurate = accuracyDelta < 0;
|
|
74
|
+
const isLessAccurate = accuracyDelta > 0;
|
|
75
|
+
const isSignificantlyLessAccurate =
|
|
76
|
+
accuracyDelta > SIGNIFICANT_ACCURACY_DIFFERENCE_METERS;
|
|
77
|
+
|
|
78
|
+
// Determine if location is newer
|
|
79
|
+
const isNewer = timeDelta > 0;
|
|
80
|
+
|
|
81
|
+
// Check if from same provider
|
|
82
|
+
const isFromSameProvider = newLocation.provider === currentBest.provider;
|
|
83
|
+
|
|
84
|
+
// Evaluate location quality based on accuracy and recency
|
|
85
|
+
if (isMoreAccurate) {
|
|
86
|
+
return true;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (isNewer && !isLessAccurate) {
|
|
90
|
+
return true;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (isNewer && !isSignificantlyLessAccurate && isFromSameProvider) {
|
|
94
|
+
return true;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return false;
|
|
98
|
+
}
|
package/README.md
DELETED
|
@@ -1,318 +0,0 @@
|
|
|
1
|
-
# react-native-nitro-geolocation
|
|
2
|
-
|
|
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
|
-

|
|
16
|
-
|
|
17
|
-
---
|
|
18
|
-
|
|
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
|
|
60
|
-
|
|
61
|
-
---
|
|
62
|
-
|
|
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
|
|
82
|
-
|
|
83
|
-
---
|
|
84
|
-
|
|
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
|
-
~~~
|
|
102
|
-
|
|
103
|
-
---
|
|
104
|
-
|
|
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
|
-
~~~
|
|
115
|
-
|
|
116
|
-
---
|
|
117
|
-
|
|
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
|
-
~~~
|
|
132
|
-
|
|
133
|
-
---
|
|
134
|
-
|
|
135
|
-
### 4. Usage Example
|
|
136
|
-
|
|
137
|
-
~~~tsx
|
|
138
|
-
import Geolocation from 'react-native-nitro-geolocation';
|
|
139
|
-
|
|
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
|
-
~~~
|
|
159
|
-
|
|
160
|
-
---
|
|
161
|
-
|
|
162
|
-
### Migrating from `@react-native-community/geolocation`
|
|
163
|
-
|
|
164
|
-
Nitro Geolocation is **100% API-compatible** with the original package.
|
|
165
|
-
You can migrate simply by replacing imports:
|
|
166
|
-
|
|
167
|
-
~~~diff
|
|
168
|
-
- import Geolocation from '@react-native-community/geolocation';
|
|
169
|
-
+ import Geolocation from 'react-native-nitro-geolocation';
|
|
170
|
-
~~~
|
|
171
|
-
|
|
172
|
-
**Benefits:**
|
|
173
|
-
- Better performance via JSI
|
|
174
|
-
- Reduced bridge overhead
|
|
175
|
-
- Improved permission consistency
|
|
176
|
-
- Built-in TypeScript definitions
|
|
177
|
-
|
|
178
|
-
---
|
|
179
|
-
|
|
180
|
-
## 🧠 API Methods
|
|
181
|
-
|
|
182
|
-
### Summary
|
|
183
|
-
- `setRNConfiguration`
|
|
184
|
-
- `requestAuthorization`
|
|
185
|
-
- `getCurrentPosition`
|
|
186
|
-
- `watchPosition`
|
|
187
|
-
- `clearWatch`
|
|
188
|
-
- `stopObserving`
|
|
189
|
-
|
|
190
|
-
---
|
|
191
|
-
|
|
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
|
-
});
|
|
205
|
-
|
|
206
|
-
// recommended
|
|
207
|
-
import { setRNConfiguration } from 'react-native-nitro-geolocation';
|
|
208
|
-
|
|
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)*
|
|
222
|
-
|
|
223
|
-
---
|
|
224
|
-
|
|
225
|
-
### `requestAuthorization()`
|
|
226
|
-
|
|
227
|
-
Requests location permission from the system.
|
|
228
|
-
|
|
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),
|
|
235
|
-
);
|
|
236
|
-
|
|
237
|
-
// recommended
|
|
238
|
-
import { requestAuthorization } from 'react-native-nitro-geolocation';
|
|
239
|
-
|
|
240
|
-
requestAuthorization(
|
|
241
|
-
() => console.log('Permission granted'),
|
|
242
|
-
(error) => console.error('Permission error:', error),
|
|
243
|
-
);
|
|
244
|
-
~~~
|
|
245
|
-
|
|
246
|
-
---
|
|
247
|
-
|
|
248
|
-
### `getCurrentPosition()`
|
|
249
|
-
|
|
250
|
-
Retrieves the current device location once.
|
|
251
|
-
|
|
252
|
-
~~~tsx
|
|
253
|
-
import Geolocation from 'react-native-nitro-geolocation';
|
|
254
|
-
|
|
255
|
-
Geolocation.getCurrentPosition(
|
|
256
|
-
(position) => console.log(position),
|
|
257
|
-
(error) => console.error(error),
|
|
258
|
-
{ enableHighAccuracy: true, timeout: 15000, maximumAge: 10000 },
|
|
259
|
-
);
|
|
260
|
-
|
|
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
|
-
~~~
|
|
270
|
-
|
|
271
|
-
---
|
|
272
|
-
|
|
273
|
-
### `watchPosition()`
|
|
274
|
-
|
|
275
|
-
Watches location changes and calls the success callback each time.
|
|
276
|
-
|
|
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';
|
|
288
|
-
|
|
289
|
-
const id = watchPosition(
|
|
290
|
-
(position) => console.log('Position:', position),
|
|
291
|
-
(error) => console.error(error),
|
|
292
|
-
{ interval: 5000, distanceFilter: 10 },
|
|
293
|
-
);
|
|
294
|
-
|
|
295
|
-
~~~
|
|
296
|
-
|
|
297
|
-
---
|
|
298
|
-
|
|
299
|
-
### `clearWatch()`
|
|
300
|
-
|
|
301
|
-
Stops watching location updates for a given watch ID.
|
|
302
|
-
|
|
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
|
-
---
|
|
313
|
-
|
|
314
|
-
## 🧪 Summary
|
|
315
|
-
|
|
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.
|
package/src/clearWatch.ts
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { NitroModules } from "react-native-nitro-modules";
|
|
2
|
-
import type { NitroGeolocation } from "./NitroGeolocation.nitro";
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Clears a specific watch session identified by watchId.
|
|
6
|
-
*
|
|
7
|
-
* @param watchId - The ID returned by watchPosition()
|
|
8
|
-
*/
|
|
9
|
-
export function clearWatch(watchId: number): void {
|
|
10
|
-
const nitroGeolocation =
|
|
11
|
-
NitroModules.createHybridObject<NitroGeolocation>("NitroGeolocation");
|
|
12
|
-
nitroGeolocation.clearWatch(watchId);
|
|
13
|
-
}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import { NitroGeolocationHybridObject } from "./NitroGeolocationModule";
|
|
2
|
-
import type { GeolocationError } from "./types";
|
|
3
|
-
|
|
4
|
-
export function requestAuthorization(
|
|
5
|
-
success?: () => void,
|
|
6
|
-
error?: (error: GeolocationError) => void
|
|
7
|
-
): void {
|
|
8
|
-
NitroGeolocationHybridObject.requestAuthorization(success, error);
|
|
9
|
-
}
|