abidibo.net

Geolocation with react-native

geolocation react-native

I've had many problems with react-native geolocation module.

In particular I faced a weird behaviour of the getCurrentPosition method: while the world was lamenting timeout problems, probably due to the fact that gps tracking is not fast at all in closed spaces, my problem was that with highAccuracy set to true, the returned value was always a cached one, no matter how I set maxAge option.

If your problem is a timeout problem, then you can just call getCurrentPosition with highAccuracy set to false on timeout.

In my case I've tried to solve the problem using the watchPosition method, which in my tests seems not tu suffer of the cache problem. So the idea is the following.

When asking for position, the first attempt is to retrieve GPS position using watchPosition method:

  • if the position is retrieved, then the watch listener is canceled and the provided callback is called;
  • if an error occurs, the watch listener is canceled and the function tries to retrieve a low accuracy position
  • after the watchPosition call, a timeout function is set. This function checks if the watchPosition method returned an error or a success, in either cases does nothing. But if the watchPosition method still is running, then it performs a low accuracy call. This way a low accuracy position is immediately returned to the user, and later on, if the high accuracy call retrieves something, the user gets the updated position.

Here comes the code, all kinds of suggestions are much appreciated

export function getLocation (cb, options) {
  let highAccuracySuccess = false
  let highAccuracyError = false
  let highAccuracy = !options || options.highAccuracy === undefined ? true : options.highAccuracy
  let timeout = !options || options.timeout === undefined ? 10000 : options.timeout

  let getLowAccuracyPosition = () => {
    console.log('REQUESTING POSITION', 'HIGH ACCURACY FALSE')
    navigator.geolocation.getCurrentPosition(
      position => {
        console.log('POSITION NETWORK OK', position)
        cb(position.coords)
      },
      error => {
        console.log(error)
        // inform  the user
      },
      {
        enableHighAccuracy: false,
        timeout: 10000,
        maxAge: 0
      }
    )
  }

  if (highAccuracy) {
    console.log('REQUESTING POSITION', 'HIGH ACCURACY TRUE')
    const watchId = navigator.geolocation.watchPosition(
      position => {
        // location retrieved
        highAccuracySuccess = true
        console.log('POSITION GPS OK', position)
        navigator.geolocation.clearWatch(watchId)
        cb(position.coords)
      },
      error => {
        console.log(error)
        highAccuracyError = true
        navigator.geolocation.clearWatch(watchId)
        getLowAccuracyPosition()
      },
      {
        enableHighAccuracy: true,
        timeout: 20000,
        maxAge: 0,
        distanceFilter: 1
      }
    )

    setTimeout(() => {
      if (!highAccuracySuccess && !highAccuracyError) {
        getLowAccuracyPosition()
      }
    }, timeout)
  }
}

I use toasts to inform the user about errors directly in this function (I've stripped out such parts), but you can easily add an onError callback.

Subscribe to abidibo.net!

If you want to stay up to date with new contents published on this blog, then just enter your email address, and you will receive blog updates! You can set you preferences and decide to receive emails only when articles are posted regarding a precise topic.

I promise, you'll never receive spam or advertising of any kind from this subscription, just content updates.

* indicates required

abidibo.net topics

Comments are welcome!

blog comments powered by Disqus

Your Smartwatch Loves Tasker!

Your Smartwatch Loves Tasker!

Now available for purchase!

Featured