How to fix [Unhandled promise rejection: Error: Location provider is unavailable. Make sure that location services are enabled.]

Viewed 9757

I have just upgraded my app from Expo SDK 37.0.0 to 38.0.0. The app works fine on iOS but on Android I get the following warning and the app doesn't geolocate me on the map.

Development environment :

  • Expo SDK 38.0.0 (managed workflow)
  • React Native 0.62
  • Maps provider : Google Maps on Android
  • react-native-maps: 0.27.1
  • React: 16.11.0
  • Device : Honor 8X/Android 10

Expected result : The app should geolocate me (the user) based on my position. Actual result : The app doesn't geolocate me (the user) based on my position. Warning :

[Unhandled promise rejection: Error: Location provider is unavailable. Make sure that location services are enabled.]

What have I tried so far?

  1. Ran expo upgrade once more to ensure that all of your packages are set to the correct version.

  2. Deleted package-lock.json and node_modules and ran npm install.

  3. Set Location.getCurrentPositionAsync({accuracy:Location.Accuracy.High})

  4. Set Location.getCurrentPositionAsync({ enableHighAccuracy: true })

    import * as Location from 'expo-location';
    import * as Permissions from 'expo-permissions';
    
    
    async _getLocationAsync() {
      let { status } = await Permissions.askAsync(Permissions.LOCATION);
      if (status !== 'granted') {
        /* If user hasn't granted permission to geolocate himself herself */
        Alert.alert(
          "User location not detected",
          "You haven't granted permission to detect your location.",
          [{ text: 'OK', onPress: () => console.log('OK Pressed') }]
        );
      }
    
      let location = await Location.getCurrentPositionAsync({ accuracy: Location.Accuracy.High });
      this.setState({
        userLat: location.coords.latitude,
        userLng: location.coords.longitude,
        navGeoStatus: true,
        lat: location.coords.latitude,
        lng: location.coords.longitude
      });
    }```
    
11 Answers

If anyone is still fighting with this problem - please check if you have added:

 "android": {
  "permissions": ["ACCESS_BACKGROUND_LOCATION"]
},

in your app.json file

change

let location = await Location.getCurrentPositionAsync({});

for:

let location = await Location.getLastKnownPositionAsync({
          accuracy: 6,
        });

I've tried all of the other solutions above, and nothing works. The solution actually works below.

Use this :

await Location.getLastKnownPositionAsync({});

instead of :

await Location.getCurrentPositionAsync({});

Edited:

I've come up with a new solution if you wanted to use getCurrentPosition, not the last known position. You can use this code below

export default async function getLocation() {
  await Location.enableNetworkProviderAsync().then().catch(_ => null);
  const status = await Location.hasServicesEnabledAsync();
  if(status){
    const getCurrentPosition = async () => await Location.getCurrentPositionAsync()
                                      .then(loc => loc)
                                      .catch(_ => null)
    let location = await getCurrentPosition();
    while(location === null){
      location = await getCurrentPosition();
    }
    return location;
  }else{
    throw new Error("Please activate the location");
  }
}

I solved this problem like this:

Location.Accuracy.Balanced

changed to

Location.LocationAccuracy.Balanced

I am still getting this problem in September 2021

A cut and paste of the current EXPO location guide is giving the same error in this question. https://docs.expo.dev/versions/latest/sdk/location/

My solution was to replace

let location = await Location.getCurrentPositionAsync({});
setLocation(location);

with

await Location.watchPositionAsync({ enableHighAccuracy: true }, (loc) => setLocation(loc));

And it worked immediately.

I was only testing getCurrentPositionAsync as 'iteration 1' with a view to eventually using watchPositionAsync anyway. I spent too much time trying to get current position to work when I didn't need it.

So this solution would suit if you want regular updates of the phone's location rather than just a one time update.

Link to watchPositionAsync documentation

let location: any = await Location.getCurrentPositionAsync({ enableHighAccuracy: true });

for me it worked, when i added enableHighAccuracy: true in Location.getCurrentPositionAsync.

In my case App with below mentioned code was working fine in Android Phone (S8) But had the above issue with the android emulator. Please refer to the spec I had. After multiple attempts I have upgraded expo SDK which solved the issue.

Short Answer: Upgrade Expo SDK to version 41

Spec I had previously :

Expo SDK: 40
NPM: 6.14.11
Android Studio: 4.1.1
Virtual Device: API 30

Code: Example code by Expo documentation

import React, { useState, useEffect } from 'react';
import { Platform, Text, View, StyleSheet } from 'react-native';
import * as Location from 'expo-location';

export default function App() {
  const [location, setLocation] = useState(null);
  const [errorMsg, setErrorMsg] = useState(null);

  useEffect(() => {
    (async () => {
      let { status } = await Location.requestForegroundPermissionsAsync();
      if (status !== 'granted') {
        setErrorMsg('Permission to access location was denied');
        return;
      }

      let location = await Location.getCurrentPositionAsync({});
      setLocation(location);
    })();
  }, []);

  let text = 'Waiting..';
  if (errorMsg) {
    text = errorMsg;
  } else if (location) {
    text = JSON.stringify(location);
  }

  return (
    <View style={styles.container}>
      <Text style={styles.paragraph}>{text}</Text>
    </View>
  );
}

Solution worked for me:

expo upgrade
  • expo: ~4.8.1
  • Google Maps on Android
  • react: ~16.13.1

Had the same problem.

How I managed to fix it?

Location.getCurrentPositionAsync({accuracy: Location.Accuracy.Highest});

using accuracy as Highest is important to fix this issue

Hope it works for you

Few days back I got stucked on same problem, might be Expo Location module is having some issues. For the time solution is to wrap the location related code in try catch, run until you got your location object.

Like so :

let location;
let locationSuccess = false;
while (!locationSuccess) {
  try {
    location = await Location.getCurrentPositionAsync({
      accuracy: Location.Accuracy.High,
    });
    locationSuccess = true;
  } catch (ex) {
    console.log("retring....");
  }
}
console.log("Location",location)

Do you can use getLastKnownPositionAsync how 2nd option:

await Location.requestPermissionsAsync();

Location.getCurrentPositionAsync({accuracy: Location.Accuracy.High})
    .then(location => console.log(location))
    .catch(() => {
        Location.getLastKnownPositionAsync({accuracy: 6})
            .then(location => console.log(location));
    });

It seems like user has granted permission to the app to use location. But this warning occurs when location services in the phone itself hasn't been enabled. search for it in the settings and enable it

Edited answer (added code to handle warning):

let gpsServiceStatus = await Location.hasServicesEnabledAsync();
      if (gpsServiceStatus) {
let location = await Location.getCurrentPositionAsync({ accuracy: Location.Accuracy.High });
  this.setState({
    userLat: location.coords.latitude,
    userLng: location.coords.longitude,
    navGeoStatus: true,
    lat: location.coords.latitude,
    lng: location.coords.longitude
  });
} else {
        alert("Enable Location services"); //or any code to handle if location service is disabled otherwise
      }
Related