Shidhin Cr
Shidhin Cr

Reputation: 868

Retry Geolocation request without refreshing the browser

I have a specific issue with the Geolocation api. This is my scenario:

  1. User landed on a page ( in Chrome - Android ) with GPS location disabled.
  2. There is a button on the page, and onClick of the button triggers the Geolocation.getCurrentPosition
  3. Geolocation goes to the error callback with error message “User denied Geolocation”
  4. User goes to Android settings ( mostly in notification drawer ) and turn on the location
  5. User click the button again ( at this time, location is available ) to get the coordinates
  6. However, Geolocation api still throws the error “User denied Geolocation”

  1. At this time, the geolocation request will work only if the user refreshes the page and press the button ( note: the location is still enabled )

Is there a way to make this work without the browser refresh ?

Here is the jsbin link: https://output.jsbin.com/pihenud

Upvotes: 2

Views: 2630

Answers (1)

Shidhin Cr
Shidhin Cr

Reputation: 868

Finally, I was able to solve this problem using an iFrame hack.

Here is the solution:

Instead of asking the permission in the main window, create an iFrame dynamically and call the geolocation.getCurrentPosition inside it. Now, we can use the window.postMessage to pass the position data to the parent browser window.

When we have to retry the geolocation request again, we just need to reload the iframe -- This will have the new site settings.

Here is the iframe code if anyone wants to try:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Namshi Geolocation</title>
</head>
<body>
  <script type="text/javascript">
    var sendMessage = function(result){
      window.postMessage(JSON.stringify(result), window.location.origin);
    };

    var triggerGeolocationRequest = function(){
      var options = {
        enableHighAccuracy: true,
        timeout: 10000,
        maximumAge: 0
      };

      var result;

      if(window.navigator.geolocation){
        window.navigator.geolocation.getCurrentPosition(function(position){
          var result = {
            type: 'success',
            data: {lat: position.coords.latitude, lng: position.coords.longitude}
          };
          sendMessage(result);
        }, function(err){
          var result = {
            type: 'error',
            data: { message: err.message, code: err.code }
          };
          sendMessage(result);
        }, options)
      } else {
        result = {
          type: 'error',
          data: { message: 'No Geolocation API' }
        };
        sendMessage(result);
      }
    };
    window.addEventListener('load', triggerGeolocationRequest);
  </script>
</body>
</html>

And in your application code, you can have a utility to inject the iFrame. See the below code:

utils.getCurrentPosition = function(){
  return new Promise(function(resolve, reject){
    var ifr = document.createElement('iframe');
    ifr.style.opacity = '0';
    ifr.style.pointerEvents = 'none';
    ifr.src = location.origin + '/geo.html'; // the previous html code.

    document.body.appendChild(ifr);

    ifr.contentWindow.addEventListener('message', function(message){
      message = JSON.parse(message.data);
      if(message.type === 'success'){
        resolve(message.data);
      } else {
        reject(message.data);
      }
      document.body.removeChild(ifr);
    });
  });
};

Upvotes: 5

Related Questions