1import { PermissionStatus, createPermissionHook, Platform, } from 'expo-modules-core'; 2import ExpoLocation from './ExpoLocation'; 3import { LocationAccuracy, LocationActivityType, LocationGeofencingEventType, LocationGeofencingRegionState, } from './Location.types'; 4import { LocationEventEmitter } from './LocationEventEmitter'; 5import { LocationSubscriber, HeadingSubscriber, _getCurrentWatchId } from './LocationSubscribers'; 6// @needsAudit 7/** 8 * @deprecated The Geocoding web api is no longer available from SDK 49 onwards. Use [Place Autocomplete](https://developers.google.com/maps/documentation/places/web-service/autocomplete) instead. 9 * @param apiKey Google API key obtained from Google API Console. This API key must have `Geocoding API` 10 * enabled, otherwise your geocoding requests will be denied. 11 */ 12function setGoogleApiKey(_apiKey) { } 13// @needsAudit 14/** 15 * Check status of location providers. 16 * @return A promise which fulfills with an object of type [LocationProviderStatus](#locationproviderstatus). 17 */ 18export async function getProviderStatusAsync() { 19 return ExpoLocation.getProviderStatusAsync(); 20} 21// @needsAudit 22/** 23 * Asks the user to turn on high accuracy location mode which enables network provider that uses 24 * Google Play services to improve location accuracy and location-based services. 25 * @return A promise resolving as soon as the user accepts the dialog. Rejects if denied. 26 */ 27export async function enableNetworkProviderAsync() { 28 // If network provider is disabled (user's location mode is set to "Device only"), 29 // Android's location provider may not give you any results. Use this method in order to ask the user 30 // to change the location mode to "High accuracy" which uses Google Play services and enables network provider. 31 // `getCurrentPositionAsync` and `watchPositionAsync` are doing it automatically anyway. 32 if (Platform.OS === 'android') { 33 return ExpoLocation.enableNetworkProviderAsync(); 34 } 35} 36// @needsAudit 37/** 38 * Requests for one-time delivery of the user's current location. 39 * Depending on given `accuracy` option it may take some time to resolve, 40 * especially when you're inside a building. 41 * > __Note:__ Calling it causes the location manager to obtain a location fix which may take several 42 * > seconds. Consider using [`Location.getLastKnownPositionAsync`](#locationgetlastknownpositionasyncoptions) 43 * > if you expect to get a quick response and high accuracy is not required. 44 * @param options 45 * @return A promise which fulfills with an object of type [`LocationObject`](#locationobject). 46 */ 47export async function getCurrentPositionAsync(options = {}) { 48 return ExpoLocation.getCurrentPositionAsync(options); 49} 50// @needsAudit 51/** 52 * Gets the last known position of the device or `null` if it's not available or doesn't match given 53 * requirements such as maximum age or required accuracy. 54 * It's considered to be faster than `getCurrentPositionAsync` as it doesn't request for the current 55 * location, but keep in mind the returned location may not be up-to-date. 56 * @param options 57 * @return A promise which fulfills with an object of type [LocationObject](#locationobject) or 58 * `null` if it's not available or doesn't match given requirements such as maximum age or required 59 * accuracy. 60 */ 61export async function getLastKnownPositionAsync(options = {}) { 62 return ExpoLocation.getLastKnownPositionAsync(options); 63} 64// @needsAudit 65/** 66 * Subscribe to location updates from the device. Please note that updates will only occur while the 67 * application is in the foreground. To get location updates while in background you'll need to use 68 * [Location.startLocationUpdatesAsync](#locationstartlocationupdatesasynctaskname-options). 69 * @param options 70 * @param callback This function is called on each location update. It receives an object of type 71 * [`LocationObject`](#locationobject) as the first argument. 72 * @return A promise which fulfills with a [`LocationSubscription`](#locationsubscription) object. 73 */ 74export async function watchPositionAsync(options, callback) { 75 const watchId = LocationSubscriber.registerCallback(callback); 76 await ExpoLocation.watchPositionImplAsync(watchId, options); 77 return { 78 remove() { 79 LocationSubscriber.unregisterCallback(watchId); 80 }, 81 }; 82} 83// @needsAudit 84/** 85 * Gets the current heading information from the device. To simplify, it calls `watchHeadingAsync` 86 * and waits for a couple of updates, and then returns the one that is accurate enough. 87 * @return A promise which fulfills with an object of type [LocationHeadingObject](#locationheadingobject). 88 */ 89export async function getHeadingAsync() { 90 return new Promise(async (resolve) => { 91 let tries = 0; 92 const subscription = await watchHeadingAsync((heading) => { 93 if (heading.accuracy > 1 || tries > 5) { 94 subscription.remove(); 95 resolve(heading); 96 } 97 else { 98 tries += 1; 99 } 100 }); 101 }); 102} 103// @needsAudit 104/** 105 * Subscribe to compass updates from the device. 106 * @param callback This function is called on each compass update. It receives an object of type 107 * [LocationHeadingObject](#locationheadingobject) as the first argument. 108 * @return A promise which fulfills with a [`LocationSubscription`](#locationsubscription) object. 109 */ 110export async function watchHeadingAsync(callback) { 111 const watchId = HeadingSubscriber.registerCallback(callback); 112 await ExpoLocation.watchDeviceHeading(watchId); 113 return { 114 remove() { 115 HeadingSubscriber.unregisterCallback(watchId); 116 }, 117 }; 118} 119// @needsAudit 120/** 121 * Geocode an address string to latitude-longitude location. 122 * > **Note**: Using the Geocoding web api is no longer supported. Use [Place Autocomplete](https://developers.google.com/maps/documentation/places/web-service/autocomplete) instead. 123 * 124 * > **Note**: Geocoding is resource consuming and has to be used reasonably. Creating too many 125 * > requests at a time can result in an error, so they have to be managed properly. 126 * > It's also discouraged to use geocoding while the app is in the background and its results won't 127 * > be shown to the user immediately. 128 * 129 * > On Android, you must request a location permission (`Permissions.LOCATION`) from the user 130 * > before geocoding can be used. 131 * @param address A string representing address, eg. `"Baker Street London"`. 132 * @param options 133 * @return A promise which fulfills with an array (in most cases its size is 1) of [`LocationGeocodedLocation`](#locationgeocodedlocation) objects. 134 */ 135export async function geocodeAsync(address, options) { 136 if (typeof address !== 'string') { 137 throw new TypeError(`Address to geocode must be a string. Got ${address} instead.`); 138 } 139 if (options?.useGoogleMaps || Platform.OS === 'web') { 140 if (__DEV__) { 141 console.warn('The Geocoding API has been removed in SDK 49, use Place Autocomplete service instead' + 142 '(https://developers.google.com/maps/documentation/places/web-service/autocomplete)'); 143 } 144 return []; 145 } 146 return await ExpoLocation.geocodeAsync(address); 147} 148// @needsAudit 149/** 150 * Reverse geocode a location to postal address. 151 * > **Note**: Using the Geocoding web api is no longer supported. Use [Place Autocomplete](https://developers.google.com/maps/documentation/places/web-service/autocomplete) instead. 152 * 153 * > **Note**: Geocoding is resource consuming and has to be used reasonably. Creating too many 154 * > requests at a time can result in an error, so they have to be managed properly. 155 * > It's also discouraged to use geocoding while the app is in the background and its results won't 156 * > be shown to the user immediately. 157 * 158 * > On Android, you must request a location permission (`Permissions.LOCATION`) from the user 159 * > before geocoding can be used. 160 * @param location An object representing a location. 161 * @param options 162 * @return A promise which fulfills with an array (in most cases its size is 1) of [`LocationGeocodedAddress`](#locationgeocodedaddress) objects. 163 */ 164export async function reverseGeocodeAsync(location, options) { 165 if (typeof location.latitude !== 'number' || typeof location.longitude !== 'number') { 166 throw new TypeError('Location to reverse-geocode must be an object with number properties `latitude` and `longitude`.'); 167 } 168 if (options?.useGoogleMaps || Platform.OS === 'web') { 169 if (__DEV__) { 170 console.warn('The Geocoding API has been removed in SDK 49, use Place Autocomplete service instead' + 171 '(https://developers.google.com/maps/documentation/places/web-service/autocomplete)'); 172 } 173 return []; 174 } 175 return await ExpoLocation.reverseGeocodeAsync(location); 176} 177// @needsAudit 178/** 179 * Checks user's permissions for accessing location. 180 * @return A promise that fulfills with an object of type [LocationPermissionResponse](#locationpermissionresponse). 181 * @deprecated Use [`getForegroundPermissionsAsync`](#locationgetforegroundpermissionsasync) or [`getBackgroundPermissionsAsync`](#locationgetbackgroundpermissionsasync) instead. 182 */ 183export async function getPermissionsAsync() { 184 console.warn(`"getPermissionsAsync()" is now deprecated. Please use "getForegroundPermissionsAsync()" or "getBackgroundPermissionsAsync()" instead.`); 185 return await ExpoLocation.getPermissionsAsync(); 186} 187// @needsAudit 188/** 189 * Asks the user to grant permissions for location. 190 * @return A promise that fulfills with an object of type [LocationPermissionResponse](#locationpermissionresponse). 191 * @deprecated Use [`requestForegroundPermissionsAsync`](#locationrequestforegroundpermissionsasync) or [`requestBackgroundPermissionsAsync`](#locationrequestbackgroundpermissionsasync) instead. 192 */ 193export async function requestPermissionsAsync() { 194 console.warn(`"requestPermissionsAsync()" is now deprecated. Please use "requestForegroundPermissionsAsync()" or "requestBackgroundPermissionsAsync()" instead.`); 195 return await ExpoLocation.requestPermissionsAsync(); 196} 197// @needsAudit 198/** 199 * Checks user's permissions for accessing location while the app is in the foreground. 200 * @return A promise that fulfills with an object of type [PermissionResponse](#permissionresponse). 201 */ 202export async function getForegroundPermissionsAsync() { 203 return await ExpoLocation.getForegroundPermissionsAsync(); 204} 205// @needsAudit 206/** 207 * Asks the user to grant permissions for location while the app is in the foreground. 208 * @return A promise that fulfills with an object of type [PermissionResponse](#permissionresponse). 209 */ 210export async function requestForegroundPermissionsAsync() { 211 return await ExpoLocation.requestForegroundPermissionsAsync(); 212} 213// @needsAudit 214/** 215 * Check or request permissions for the foreground location. 216 * This uses both `requestForegroundPermissionsAsync` and `getForegroundPermissionsAsync` to interact with the permissions. 217 * 218 * @example 219 * ```ts 220 * const [status, requestPermission] = Location.useForegroundPermissions(); 221 * ``` 222 */ 223export const useForegroundPermissions = createPermissionHook({ 224 getMethod: getForegroundPermissionsAsync, 225 requestMethod: requestForegroundPermissionsAsync, 226}); 227// @needsAudit 228/** 229 * Checks user's permissions for accessing location while the app is in the background. 230 * @return A promise that fulfills with an object of type [PermissionResponse](#permissionresponse). 231 */ 232export async function getBackgroundPermissionsAsync() { 233 return await ExpoLocation.getBackgroundPermissionsAsync(); 234} 235// @needsAudit 236/** 237 * Asks the user to grant permissions for location while the app is in the background. 238 * On __Android 11 or higher__: this method will open the system settings page - before that happens 239 * you should explain to the user why your application needs background location permission. 240 * For example, you can use `Modal` component from `react-native` to do that. 241 * > __Note__: Foreground permissions should be granted before asking for the background permissions 242 * (your app can't obtain background permission without foreground permission). 243 * @return A promise that fulfills with an object of type [PermissionResponse](#permissionresponse). 244 */ 245export async function requestBackgroundPermissionsAsync() { 246 return await ExpoLocation.requestBackgroundPermissionsAsync(); 247} 248// @needsAudit 249/** 250 * Check or request permissions for the background location. 251 * This uses both `requestBackgroundPermissionsAsync` and `getBackgroundPermissionsAsync` to 252 * interact with the permissions. 253 * 254 * @example 255 * ```ts 256 * const [status, requestPermission] = Location.useBackgroundPermissions(); 257 * ``` 258 */ 259export const useBackgroundPermissions = createPermissionHook({ 260 getMethod: getBackgroundPermissionsAsync, 261 requestMethod: requestBackgroundPermissionsAsync, 262}); 263// --- Location service 264// @needsAudit 265/** 266 * Checks whether location services are enabled by the user. 267 * @return A promise which fulfills to `true` if location services are enabled on the device, 268 * or `false` if not. 269 */ 270export async function hasServicesEnabledAsync() { 271 return await ExpoLocation.hasServicesEnabledAsync(); 272} 273// --- Background location updates 274function _validateTaskName(taskName) { 275 if (!taskName || typeof taskName !== 'string') { 276 throw new Error(`\`taskName\` must be a non-empty string. Got ${taskName} instead.`); 277 } 278} 279// @docsMissing 280export async function isBackgroundLocationAvailableAsync() { 281 const providerStatus = await getProviderStatusAsync(); 282 return providerStatus.backgroundModeEnabled; 283} 284// @needsAudit 285/** 286 * Registers for receiving location updates that can also come when the app is in the background. 287 * 288 * # Task parameters 289 * 290 * Background location task will be receiving following data: 291 * - `locations` - An array of the new locations. 292 * 293 * ```ts 294 * import * as TaskManager from 'expo-task-manager'; 295 * 296 * TaskManager.defineTask(YOUR_TASK_NAME, ({ data: { locations }, error }) => { 297 * if (error) { 298 * // check `error.message` for more details. 299 * return; 300 * } 301 * console.log('Received new locations', locations); 302 * }); 303 * ``` 304 * 305 * @param taskName Name of the task receiving location updates. 306 * @param options An object of options passed to the location manager. 307 * 308 * @return A promise resolving once the task with location updates is registered. 309 */ 310export async function startLocationUpdatesAsync(taskName, options = { accuracy: LocationAccuracy.Balanced }) { 311 _validateTaskName(taskName); 312 await ExpoLocation.startLocationUpdatesAsync(taskName, options); 313} 314// @needsAudit 315/** 316 * Stops geofencing for specified task. 317 * @param taskName Name of the background location task to stop. 318 * @return A promise resolving as soon as the task is unregistered. 319 */ 320export async function stopLocationUpdatesAsync(taskName) { 321 _validateTaskName(taskName); 322 await ExpoLocation.stopLocationUpdatesAsync(taskName); 323} 324// @needsAudit 325/** 326 * @param taskName Name of the location task to check. 327 * @return A promise which fulfills with boolean value indicating whether the location task is 328 * started or not. 329 */ 330export async function hasStartedLocationUpdatesAsync(taskName) { 331 _validateTaskName(taskName); 332 return ExpoLocation.hasStartedLocationUpdatesAsync(taskName); 333} 334// --- Geofencing 335function _validateRegions(regions) { 336 if (!regions || regions.length === 0) { 337 throw new Error('Regions array cannot be empty. Use `stopGeofencingAsync` if you want to stop geofencing all regions'); 338 } 339 for (const region of regions) { 340 if (typeof region.latitude !== 'number') { 341 throw new TypeError(`Region's latitude must be a number. Got '${region.latitude}' instead.`); 342 } 343 if (typeof region.longitude !== 'number') { 344 throw new TypeError(`Region's longitude must be a number. Got '${region.longitude}' instead.`); 345 } 346 if (typeof region.radius !== 'number') { 347 throw new TypeError(`Region's radius must be a number. Got '${region.radius}' instead.`); 348 } 349 } 350} 351// @needsAudit 352/** 353 * Starts geofencing for given regions. When the new event comes, the task with specified name will 354 * be called with the region that the device enter to or exit from. 355 * If you want to add or remove regions from already running geofencing task, you can just call 356 * `startGeofencingAsync` again with the new array of regions. 357 * 358 * # Task parameters 359 * 360 * Geofencing task will be receiving following data: 361 * - `eventType` - Indicates the reason for calling the task, which can be triggered by entering or exiting the region. 362 * See [GeofencingEventType](#geofencingeventtype). 363 * - `region` - Object containing details about updated region. See [LocationRegion](#locationregion) for more details. 364 * 365 * @param taskName Name of the task that will be called when the device enters or exits from specified regions. 366 * @param regions Array of region objects to be geofenced. 367 * 368 * @return A promise resolving as soon as the task is registered. 369 * 370 * @example 371 * ```ts 372 * import { GeofencingEventType } from 'expo-location'; 373 * import * as TaskManager from 'expo-task-manager'; 374 * 375 * TaskManager.defineTask(YOUR_TASK_NAME, ({ data: { eventType, region }, error }) => { 376 * if (error) { 377 * // check `error.message` for more details. 378 * return; 379 * } 380 * if (eventType === GeofencingEventType.Enter) { 381 * console.log("You've entered region:", region); 382 * } else if (eventType === GeofencingEventType.Exit) { 383 * console.log("You've left region:", region); 384 * } 385 * }); 386 * ``` 387 */ 388export async function startGeofencingAsync(taskName, regions = []) { 389 _validateTaskName(taskName); 390 _validateRegions(regions); 391 await ExpoLocation.startGeofencingAsync(taskName, { regions }); 392} 393// @needsAudit 394/** 395 * Stops geofencing for specified task. It unregisters the background task so the app will not be 396 * receiving any updates, especially in the background. 397 * @param taskName Name of the task to unregister. 398 * @return A promise resolving as soon as the task is unregistered. 399 */ 400export async function stopGeofencingAsync(taskName) { 401 _validateTaskName(taskName); 402 await ExpoLocation.stopGeofencingAsync(taskName); 403} 404// @needsAudit 405/** 406 * @param taskName Name of the geofencing task to check. 407 * @return A promise which fulfills with boolean value indicating whether the geofencing task is 408 * started or not. 409 */ 410export async function hasStartedGeofencingAsync(taskName) { 411 _validateTaskName(taskName); 412 return ExpoLocation.hasStartedGeofencingAsync(taskName); 413} 414export { LocationEventEmitter as EventEmitter, _getCurrentWatchId }; 415export { LocationAccuracy as Accuracy, LocationActivityType as ActivityType, LocationGeofencingEventType as GeofencingEventType, LocationGeofencingRegionState as GeofencingRegionState, PermissionStatus, setGoogleApiKey, }; 416export { installWebGeolocationPolyfill } from './GeolocationPolyfill'; 417export * from './Location.types'; 418//# sourceMappingURL=Location.js.map