Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Location.getCurrentPositionAsync() sometimes never responds or takes a very long time to respond #10756

Open
rvieceli opened this issue Oct 21, 2020 · 117 comments

Comments

@rvieceli
Copy link
Contributor

rvieceli commented Oct 21, 2020

🐛 Bug Report

I have slow performance on iOS (14), using Expo App (simulator - 11 and real device - 6s) or Standalone (real device - 6s).

Tried to add accuracy to Lowest, but I had same issue.

Works fine on Android.

Environment - output of expo diagnostics & the platform(s) you're targeting

Expo CLI 3.27.12 environment info:
    System:
      OS: macOS 10.15.7
      Shell: 5.7.1 - /bin/zsh
    Binaries:
      Node: 12.13.1 - ~/.nvm/versions/node/v12.13.1/bin/node
      Yarn: 1.22.5 - /usr/local/bin/yarn
      npm: 6.12.1 - ~/.nvm/versions/node/v12.13.1/bin/npm
      Watchman: 4.9.0 - /usr/local/bin/watchman
    Managers:
      CocoaPods: 1.9.3 - /usr/local/bin/pod
    SDKs:
      iOS SDK:
        Platforms: iOS 14.0, DriverKit 19.0, macOS 10.15, tvOS 14.0, watchOS 7.0
      Android SDK:
        API Levels: 28
        Build Tools: 30.0.2
        System Images: android-29 | Google Play Intel x86 Atom
    IDEs:
      Android Studio: 4.0 AI-193.6911.18.40.6626763
      Xcode: 12.0.1/12A7300 - /usr/bin/xcodebuild
    npmPackages:
      @expo/webpack-config: ^0.12.16 => 0.12.37 
      expo: ^39.0.3 => 39.0.3 
      react: 16.13.1 => 16.13.1 
      react-dom: 16.13.1 => 16.13.1 
      react-native: https://github.com/expo/react-native/archive/sdk-39.0.3.tar.gz => 0.63.2 
      react-native-web: ~0.13.14 => 0.13.14 
    npmGlobalPackages:
      expo-cli: 3.27.12
    Expo Workflow: managed

Reproducible Demo

import * as Location from 'expo-location';

async function getLocation() {
  const start = Date.now();
  await Location.getCurrentLocationAsync();
  console.log(Date.now() - start); // consistently around 10,100ms
}

Snack reproducible demo -> https://snack.expo.io/@rvieceli/expo-issue-10756

@rvieceli rvieceli added the needs validation Issue needs to be validated label Oct 21, 2020
@AdamJNavarro
Copy link
Contributor

Hey @rvieceli, you mention this occurred after upgrading...have you been able to reproduce this with a newly created SDK39 project as well?

@rvieceli
Copy link
Contributor Author

@AdamJNavarro I'm wrong. We got this issue after upgrade to SDK39 in standalone QA app, but I done right now a test in production with SDK38 and I had the same issue. Maybe is related with iOS14. I'm trying to download a iOS 13 simulator, but my internet don't help me.

@rvieceli
Copy link
Contributor Author

@AdamJNavarro We tested with Iphone 11 (ios14) and iphone 6 (ios12) and in both cases in SDK38 (prod) are fast, but in SDK39 (qa) are slow.

@rvieceli
Copy link
Contributor Author

@AdamJNavarro We discovery more things during the investigation.

When Precise Location is OFF, SDK 38 and 39 are very slow, if we turn ON works fine in SDK38, but SDK39 is slow.

image

@rvieceli
Copy link
Contributor Author

I'm 100% sure if is related, but after our test in SDK38, we got this error in sentry
Cannot obtain current location: Error Domain=kCLErrorDomain Code=0 "(null)"
We don't have anything in QA sentry with SDK 39.

@tenondecrpc
Copy link

tenondecrpc commented Oct 28, 2020

Try set accuracy low as below:

const location = await Location.getCurrentPositionAsync({ accuracy: isAndroid ? Location.Accuracy.Low : Location.Accuracy.Lowest, })

I set Location.Accuracy.Balanced, which caused long time to get location sometimes.
Android does not support Lowest.
Although accuracy is low, it was accurate enough, and able to get location much faster than before.

https://forums.expo.io/t/location-getcurrentpositionasync-takes-10-seconds/19714/3

@rvieceli
Copy link
Contributor Author

@tenondecrpc I need to show user position on the map, I need more precision. I will test it again

@tenondecrpc
Copy link

tenondecrpc commented Nov 16, 2020

@rvieceli I tried passing it balanced as value, and even that value worked for me, a higher value gave problems. This is my code now, including the request for permission to the user:

// Get permissions
const { status } = await Permissions.getAsync(Permissions.LOCATION); if (status !== 'granted') { return; }

// Get location
const location = await Location.getCurrentPositionAsync({ accuracy: Location.Accuracy.Balanced, });

@sharadrb
Copy link

sharadrb commented Nov 18, 2020

I am facing the same issue. Every time it takes more than 10 seconds in iOS to get location data.
To prove the theory, I changed my library to @react-native-community/geolocation to get location and everything remains as it is. With @react-native-community/geolocation, I get response within a second.
I am using expo-location 9.0.1

@fender
Copy link

fender commented Nov 27, 2020

We're getting the same issue since upgrading to 39. Our app has gotten very slow at getting a response back from this call.

@maralihart
Copy link

I followed the steps in the documentation as well as the lines stated above, but I still am stuck at "Waiting" for the location, never receiving the value

@rvieceli
Copy link
Contributor Author

Using this example https://docs.expo.io/versions/latest/sdk/location/#usage from documentation I created this snack https://snack.expo.io/@rvieceli/expo-issue-10756

I only added time result below the location result.

Android takes ~0.051 seconds to get my location
iOS takes ~10.013 seconds to do same job.

@rvieceli
Copy link
Contributor Author

I also tested different SDK versions.

Using Precise Location as ON
SDK37 -> 0.025 seconds
SDK38 -> 0.035 seconds
SDK39 -> 10.012 seconds
SDK40 -> 10.013 seconds

Using Precise Location as OFF
SDK37 -> 10.02 seconds
SDK38 -> 10.015 seconds
SDK39 -> 10.016 seconds
SDK40 -> 10.022 seconds

@guydani
Copy link

guydani commented Jan 5, 2021

are there any updates?

@maralihart
Copy link

For me, I just forgot to turn on the emulator's location, but no problem

@rvieceli
Copy link
Contributor Author

rvieceli commented Jan 5, 2021

Hey @maralihart, awesome!

My problem is also in production with standalone app.

Can you share with us our permissions, dependencies (only from expo) and your implementation if is different from expo documentation?

Thank you. have a nice day!

@migueladelgado
Copy link

Getting location was working fine for me on sdk 36 but upgrading to sdk 40 slowed it down to 10+ seconds. Any word from Expo on fixing this bug?

@callum-katene
Copy link

I am also experiencing this problem. Is there an update please?

@kyleyu714
Copy link

I am using SDK39, and having the same issue. any solution, plz?

@dennisbouwpas
Copy link

I am using SDK 40, In my case speed is a bit faster but anyway is not really acceptable: 4-6 seconds.

@migueladelgado
Copy link

So it seems that this is not a bug, and the documentation mentions this (https://docs.expo.io/versions/latest/sdk/location/).. What I ended up doing is using getLastKnownPositionAsync(), which is fast, to get the map started and then running getCurrentPositionAsync() in the background to get the more accurate location. Not the most elegant solution, but helps out.

@owencm
Copy link

owencm commented Apr 24, 2021

@rvieceli I tried passing it balanced as value, and even that value worked for me, a higher value gave problems. This is my code now, including the request for permission to the user:

// Get permissions
const { status } = await Permissions.getAsync(Permissions.LOCATION); if (status !== 'granted') { return; }

// Get location
const location = await Location.getCurrentPositionAsync({ accuracy: Location.Accuracy.Balanced, });

FYI this did not fix the issue for me on iOS 14.4.2 with Expo Go 2.19.3 and SDK 41. Latency is still ~11-12 seconds per API call. (Note when permission is being requested, iOS shows me a live preview of my current location so clearly has it already resolved to some - seemingly fine - resolution).

getLastKnownPositionAsync() does work for me in low latency on with these versions. Thanks @migueladelgado

(Minor note that getLastKnownPositionAsync didn't seem to work with RNWeb so I ended up using const location = await (Constants.platform.web ? Location.getCurrentPositionAsync() : Location.getLastKnownPositionAsync());)

@rvieceli
Copy link
Contributor Author

Live preview when IOS request permission is not under expo control. But you can have the same faster resolve using react-native-maps (showing user position).

@idodekerobo
Copy link

@rvieceli I tried passing it balanced as value, and even that value worked for me, a higher value gave problems. This is my code now, including the request for permission to the user:

// Get permissions
const { status } = await Permissions.getAsync(Permissions.LOCATION); if (status !== 'granted') { return; }

// Get location
const location = await Location.getCurrentPositionAsync({ accuracy: Location.Accuracy.Balanced, });

this sped it up for me but 100 meters is a bit problematic for my use case.
does anyone know if this is an expo issue that could be avoided by ejecting to the the bare workflow and writing native iOS code?
also considering downgrading the SDK to v38. thank you @rvieceli for doing the tests!

@ruettenm
Copy link

Any update here? We have the same issue in the latest expo SDK and we would like to use a high accuracy.

Thanks for your help.

@chrissabaitis
Copy link

Wanted to follow up here, any update? Same issue, looking for alternatives at the moment

Thanks friends

@bfreeman
Copy link

Still experiencing this issue on v 42. I'll give the getLastKnownPositionAsync work around a shot.

@chanphiromsok
Copy link

chanphiromsok commented Aug 28, 2023

Update: My issue was that I was connected to the dev-server via mobile hotspot and apparently, none of the location query functions in expo-location work when the hotspot in enabled. I tried again with a wifi connection and it started working again. I eventually added a dialog to tell the use to turn on wifi/data and disable the hotspot in case no location in returned.
now

I decided switch back to react-native-geolocation-service

@janusqa
Copy link

janusqa commented Aug 28, 2023

@MattZ6 I'm not understanding why the increment should be outside the try/catch

do {
  try {
    location = await Promise.race([
      delay(DELAY_IN_MS),
      Location.getCurrentPositionAsync(locationOptions)
    ]);

    if (!location) {
      throw new Error("Timeout");  // <---------- if you are thrown an error here it will be caught in catch below I think.
    }
  } catch (err) {
    locationError = err as Error;
    tries += 1; // 👈 can't we increment here?
  } 
} while (!location && tries <= MAX_TRIES);

The overall pattern seems to work well though!

@MattZ6
Copy link

MattZ6 commented Aug 29, 2023

Hey @janusqa!

Feel free to change it! The number of attempts to increment in the finally block is not a rule, just a matter of organization/understanding ✌️

The final code I'm using is still a little different from this :D

@chanphiromsok
Copy link

@MattZ6 I'm not understanding why the increment should be outside the try/catch

do {

  try {

    location = await Promise.race([

      delay(DELAY_IN_MS),

      Location.getCurrentPositionAsync(locationOptions)

    ]);



    if (!location) {

      throw new Error("Timeout");  // <---------- if you are thrown an error here it will be caught in catch below I think.

    }

  } catch (err) {

    locationError = err as Error;

    tries += 1; // 👈 can't we increment here?

  } 

} while (!location && tries <= MAX_TRIES);

The overall pattern seems to work well though!

depends on you need whether you want to increase only when error or both situations(success,error)

@efstathiosntonas
Copy link

Hey folks, just a side note, if you're not using LocationAccuracy.High on Android it might take longer to acquire location since the device is not using all sensors to fetch the location. More info here

@sk-phan
Copy link

sk-phan commented Sep 10, 2023

Hi guys,
I am currently working on a project which is using expo location. I tried this solutions and it worked perfectly on development env. Has anyone tested it in production yet? We have had so many issues with the location that it is super slow or never returns data.

Try set accuracy low as below:

const location = await Location.getCurrentPositionAsync({ accuracy: isAndroid ? Location.Accuracy.Low : Location.Accuracy.Lowest, })

I set Location.Accuracy.Balanced, which caused long time to get location sometimes. Android does not support Lowest. Although accuracy is low, it was accurate enough, and able to get location much faster than before.

https://forums.expo.io/t/location-getcurrentpositionasync-takes-10-seconds/19714/3

@Saad-Bashar
Copy link

@sk-phan , it works perfectly for me in dev build as well, however on release build it takes more than 10 seconds in iOS.

@m-regragui
Copy link

m-regragui commented Sep 25, 2023

Hi, i'm facing almost the same issue, expo-location works fine for me in dev with Location.getCurrentPositionAsync() or Location.getLastKnownPositionAsync() but it doesn't work on production.

I'm on SDK 49 and expo-location 16.1.0, i've tried many things including the solution of @sk-phan, or change the play-services-location version in the build.gradle to 20 or 21.0.1.

Nothing worked. I managed to get the error message that shows only on production:

Error: Encountered an exception while calling native method: Exception occurred while executing exported method getLastKnownPositionAsync on module Expo Location: Found interface com.google.android.gms.lo cation.FusedLocation ProviderClient, but class was expected (declaration of 'com.google.android.gms.locati on.FusedLocation ProviderClient' appears in /data/app/

I don't know what to do anymore, i'm on free plan on Expo and i've done my 30 builds this month just to try to resolve this issue, if someone has an new idea, i would like to test it... next month 🤣

@sk-phan
Copy link

sk-phan commented Sep 26, 2023

@m-regragui We decided to use Location.watchPositionAsync, instead of Location.getCurrentPositionAsync(). And it is much faster to retrieve the data. Works great on IOS and Android.

@sk-phan
Copy link

sk-phan commented Oct 4, 2023

@m-regragui could you share how you set up the Expo watchLocation ? Maybe I can help
I am using expo location 16.1.1 and SKD 49, and it works in production.

@m-regragui
Copy link

m-regragui commented Oct 4, 2023

@sk-phan Thanks for your reply, I tried with Location.watchPositionAsync:

const [location, setLocation] = useState(null);

useEffect(() => {
    (async () => {
      let { status } = await Location.requestForegroundPermissionsAsync();
      if (status !== "granted") {
        return;
      }
      try {
        await Location.watchPositionAsync(
          { accuracy: Location.Accuracy.High },
          (loc) => {
            setLocation(loc);
          }
        );
      } catch (error) {
        alert(error);
      }
    })();
  }, []);

And I have the same issue with Location.getLastKnownPositionAsync(). It works on dev but on production I catch this error:

Error: Encountered an exception while calling native method: Exception occurred while executing exported method watchPositionImplAsync on module ExpoLocation: Found interface com.google.android.gms.lo cation.FusedLocationProviderClient, but class was expected (declaration of 'com.google.android.gms.locati on.FusedLocation ProviderClient' appears in /data/app/

I use SDK 49 with expo-location 16.1.0 and managed workflow with eas build

@sk-phan
Copy link

sk-phan commented Oct 9, 2023

@m-regragui I am not able to reproduce the issue. However, with your current code, it crashed the app for undefined reason in my local build as the subscription never stopped. In this case, I run expo prebuild in my local env. I added minor code improvement below. Hopefully, it helps and you will find a solution to your issue soon.

 const [location, setLocation] = useState(null);
let locationSubcription = null;
useEffect(() => {
    (async () => {
      let { status } = await Location.requestForegroundPermissionsAsync();
      if (status !== "granted") {
        return;
      }
      try {
       locationSubcription =  await Location.watchPositionAsync(
          {  distanceInterval: 0, // for IOS
              accuracy: Location.Accuracy.High,
              timeInterval: 10000 // for Android
           },  
          (loc) => {
            setLocation(loc);
          }
        );
      } catch (error) {
        alert(error);
      }
      
      return  () => {
            locationSubcription.remove() 
        };
    })();

  }, []);

If possible, try to add a time interval for the location watcher.

@lengziyu
Copy link

@sk-phan @m-regragui Hi,bor. I use watchPositionAsyncorgetCurrentPositionAsync Can't obtain precise positioning, with a difference of several hundred meters? Have you ever encountered it? Is there any solution?
image

          const location1 = await Location.watchPositionAsync({ accuracy: Location.Accuracy.High }
          )

          const location2 = await Location.getCurrentPositionAsync({
            accuracy: Location.Accuracy.High
          })

@Mahmoudkhoder01
Copy link

Mahmoudkhoder01 commented May 8, 2024

if (Platform.OS === "android") { currentLocation = await Location.getCurrentPositionAsync({ enableHighAccuracy: true, accuracy: Location.Accuracy.BestForNavigation, }); } else { currentLocation = await Location.getLastKnownPositionAsync({ enableHighAccuracy: true, accuracy: Location.Accuracy.BestForNavigation, }); }

The one above worked for me and It is fast on both, but sometimes the location can't be fetched and I don't know why

@sainjay
Copy link

sainjay commented May 23, 2024

bove worked for me and It is fast on both, but sometimes the location can't be fetched and I don't k

what's the difference between the if and else condition. Also i can't find that flag enableHighAccuracy where did you see that?

Can @expo-bot Expo team please take look at this long pending issues from Expo Location 🥺

@Mahmoudkhoder01
Copy link

bove worked for me and It is fast on both, but sometimes the location can't be fetched and I don't k

what's the difference between the if and else condition. Also i can't find that flag enableHighAccuracy where did you see that?

Can @expo-bot Expo team please take look at this long pending issues from Expo Location 🥺

the difference between the if and else is that on ios if you use getCurrentPositionAsync it will takes a long time to fetch the location of the user, so you have to handle it like this, but the problem is some times it doesn't take the location and you have to close the app and open it again and I don't know why and how to fix it

@hungdv2402
Copy link

hungdv2402 commented Jun 13, 2024

You guys may need!
It is a trick. we can use Location.watchPositionAsync instead of Location.getCurrentPositionAsync to get current position only one time. It also works with accuracy: LocationAccuracy.BestForNavigation productively

const getCurrentPositionOneTime = async () => {
  const position = await Location.watchPositionAsync(
    {
      accuracy: LocationAccuracy.BestForNavigation,
    },
    (location) => {
      // Handle something
      position.remove();
    }
  );
}

@leo-migliorin
Copy link

If anybody is still struggling with this problem, I think I found a quite good workaround.

  • SDK 40
  • React Native 0.73.6

I am developing an app in which I need to locate the user on the map before showing him the map itself, and I was experiencing a situation in which the map would load, and only after a few seconds (as many others pointed out) the map animated in order to reach the newly read user position, which resulted in an horrible user experience.

I fundamentally decided to use getLastKnownPositionAsync() instead of getCurrentPositionAsync(), as the first one takes a lot less time to return the position of the user (assuming it was previously "known").

To be completely sure that my app would have read the user position before using the getLastKnownPositionAsync(), I called getCurrentPositionAsync() inside my MainStack component, and everything seems to work flawlessly, I always got my position when reaching the map.

Hope this helps, worked good for my use-case!

@DevicyKenitou
Copy link

Where to upvote this fix request ? Because that's getting very annoying for an so essential features !
4 years now that this issue opened ...

@andrecrimb
Copy link

andrecrimb commented Aug 13, 2024

@DevicyKenitou I just gave up on this library and moved to another one after a few years. ⌛

@DevicyKenitou
Copy link

DevicyKenitou commented Aug 13, 2024

@DevicyKenitou I just gave up on this library and moved to another one after a few years. ⌛

Oh which one do you use or recommend that is not too complicated to use/configure on an expo rn project ? That work well for both iOS and Android ?

@andrecrimb
Copy link

@DevicyKenitou I just gave up on this library and moved to another one after a few years. ⌛

Oh which one do you use or recommend that is not too complicated to use/configure on an expo rn project ? That work well for both iOS and Android ?

IMO the best one nowadays is React Native Background Geolocation. Works quite well in both platforms 👍🏽

@DevicyKenitou
Copy link

@DevicyKenitou I just gave up on this library and moved to another one after a few years. ⌛

Oh which one do you use or recommend that is not too complicated to use/configure on an expo rn project ? That work well for both iOS and Android ?

IMO the best one nowadays is React Native Background Geolocation. Works quite well in both platforms 👍🏽

Well that's a paid one ... And I don't need the "watch position" features, just need to fetch the location of the user when needed and not constantly fetching for the location

@sainjay
Copy link

sainjay commented Aug 13, 2024

@DevicyKenitou I just gave up on this library and moved to another one after a few years. ⌛

Oh which one do you use or recommend that is not too complicated to use/configure on an expo rn project ? That work well for both iOS and Android ?

IMO the best one nowadays is React Native Background Geolocation. Works quite well in both platforms 👍🏽

i'm using React Native Background Geolocation for just Geofencing and Background Fetching. Do you recommend removing the expo-location completely and use the getCurrentPosition from BackgroundGeolocation?

Also trying out this fix recommended above to use watchPositionAsync, seems to work well in testing env.

@shuo-hiwintech
Copy link

@sk-phan @m-regragui Hi,bor. I use watchPositionAsyncorgetCurrentPositionAsync Can't obtain precise positioning, with a difference of several hundred meters? Have you ever encountered it? Is there any solution? image

          const location1 = await Location.watchPositionAsync({ accuracy: Location.Accuracy.High }
          )

          const location2 = await Location.getCurrentPositionAsync({
            accuracy: Location.Accuracy.High
          })

If you are in China, you can try to convert the WGS84 coordinates from your IOS to GCJ102.

@shuo-hiwintech
Copy link

I'm experiencing this problem as well. Any updates? (whispering)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests