1import { Platform } from 'expo-modules-core'; 2 3import ExpoLocation from './ExpoLocation'; 4import { LocationObject, LocationAccuracy, LocationOptions } from './Location.types'; 5import { LocationSubscriber } from './LocationSubscribers'; 6 7type GeolocationSuccessCallback = (data: LocationObject) => void; 8type GeolocationErrorCallback = (error: any) => void; 9 10type GeolocationOptions = { 11 enableHighAccuracy?: boolean; 12}; 13 14declare const global: any; 15 16// @needsAudit 17/** 18 * Polyfills `navigator.geolocation` for interop with the core React Native and Web API approach to geolocation. 19 */ 20export function installWebGeolocationPolyfill(): void { 21 if (Platform.OS !== 'web') { 22 // Make sure `window.navigator` is defined in the global scope. 23 if (!('window' in global)) { 24 global.window = global; 25 } 26 if (!('navigator' in global.window)) { 27 global.window.navigator = {}; 28 } 29 30 // @ts-ignore 31 window.navigator.geolocation = { 32 getCurrentPosition, 33 watchPosition, 34 clearWatch, 35 36 // We don't polyfill stopObserving, this is an internal method that probably should not even exist 37 // in react-native docs 38 stopObserving: () => {}, 39 }; 40 } 41} 42 43function convertGeolocationOptions(options: GeolocationOptions): LocationOptions { 44 return { 45 accuracy: options.enableHighAccuracy ? LocationAccuracy.High : LocationAccuracy.Balanced, 46 }; 47} 48 49function getCurrentPosition( 50 success: GeolocationSuccessCallback, 51 error: GeolocationErrorCallback = () => {}, 52 options: GeolocationOptions = {} 53): void { 54 _getCurrentPositionAsyncWrapper(success, error, options); 55} 56 57// This function exists to let us continue to return undefined from getCurrentPosition, while still 58// using async/await for the internal implementation of it 59async function _getCurrentPositionAsyncWrapper( 60 success: GeolocationSuccessCallback, 61 error: GeolocationErrorCallback, 62 options: GeolocationOptions 63): Promise<any> { 64 try { 65 await ExpoLocation.requestPermissionsAsync(); 66 const result = await ExpoLocation.getCurrentPositionAsync(convertGeolocationOptions(options)); 67 success(result); 68 } catch (e) { 69 error(e); 70 } 71} 72 73// Polyfill: navigator.geolocation.watchPosition 74function watchPosition( 75 success: GeolocationSuccessCallback, 76 error: GeolocationErrorCallback, 77 options: GeolocationOptions 78) { 79 const watchId = LocationSubscriber.registerCallback(success); 80 81 ExpoLocation.watchPositionImplAsync(watchId, options).catch((err) => { 82 LocationSubscriber.unregisterCallback(watchId); 83 error({ watchId, message: err.message, code: err.code }); 84 }); 85 86 return watchId; 87} 88 89// Polyfill: navigator.geolocation.clearWatch 90function clearWatch(watchId: number) { 91 LocationSubscriber.unregisterCallback(watchId); 92} 93