Search code examples
javascriptiosiphonegoogle-chromegeolocation

Why is Chrome iOS sending prompt when geolocation is granted


I want to allow geolocation in some sections of my website, to do so I prefer to ask for permission on the client page before prompting them with the browser geolocation permission request.

So I gather the response.state with something like the following...

navigator.permissions.query({ name: "geolocation" }).then((response) => {
  // do stuff with response.state
});

And then if the state is prompt I'll just render another page asking them nicely to allow geolocation by clicking on a button. This button triggers this code

navigator.geolocation.getCurrentPosition(
  (position) => {
    if (position) {
      // location was granted for sure, we do stuff
    }
  },
  () => {
    // this means the client didn't accept geolocation
  }
);

It works perfectly on my computer, in all browsers. However, when refreshing the page on Chrome iOS after allowing geolocation, it's still on prompt when the state should be granted; I can actually get the exact position despite the state being prompt which makes very little sense to me.

What's going here with Chrome iOS? Is there a workaround? The behavior is different but I can't pinpoint why, and can't find documentation about it. This improved UX is essential. I could just prompt it and ask for the best but I want the client to approve first.


Solution

  • In the end, Chrome iOS has an erratic behavior, so I had to figure out a workaround by myself.

    I just want to show some kind of UI when in prompt state so I added those helpers

    export function setGeoGranted() {
      localStorage.setItem("permission-granted", "true");
    }
    
    export function isGeoGranted() {
      return !!localStorage.getItem("permission-granted");
    }
    

    And when rendering the UI to prompt I just double check like the following

    !isGeoGranted() && stateGeolocation === "prompt"
    

    Finally when having the UI to grant permission, I added the logic in there too

    navigator.geolocation.getCurrentPosition(
      (position) => {
        if (position) {
          setGeoGranted();
          window.location.reload();
        }
      },
      () => {
        // this means the client didn't accept geolocation
      }
    );
    

    In my case, it works. It'll put the prompt state in doubt and ask to be sure, once the items is stored we consider this to be sure so we don't ask again and just have the logic to get the position further down.

    However, I didn't find any explanation on why Chrome behave this way, so if anyone read this and have more details, don't hesitate to comment it out.