Reputation: 4295
I have this snippet:
const getCurrentPosition = () =>
new Promise<GeolocationPosition>((resolve, reject) => {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(resolve, reject, {
timeout: 5000,
maximumAge: 2000,
enableHighAccuracy: true,
});
} else {
reject(new Error('Browser does not support geolocation!'));
}
});
Which I call like so:
try {
const { coords } = await getCurrentPosition();
// do stuff with coords
}
catch (e){
// handle the error
}
When executing this code in an iOS PWA (navigator.standalone
) if I have my location settings for Safari (Settings
> Privacy
> Location Services
> Safari Websites
) set to: Ask Next Time
, the getCurrentPosition()
promise hangs and does not timeout, resolve or reject. It does not prompt me for my location like it does in the iOS Safari browser
If I change the settings to Never
or While Using the App
, then it prompts me and works fine.
I want to be able to handle the scenario where a user has set their settings to Ask Next Time
whilst using a PWA.
Upvotes: 3
Views: 1505
Reputation: 4295
The solution to this was fairly trivial once some colleagues and I figured it out:
export function getUserPosition(): Promise<GeolocationPosition> {
const promiseArray = [];
if (navigator.standalone) {
promiseArray.push(
new Promise((resolve, reject) => {
const wait = setTimeout(() => {
clearTimeout(wait);
reject('Location has timed out');
}, 4000);
})
);
}
const getCurrentPositionPromise = new Promise((resolve, reject) => {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(resolve, reject, {
timeout: 5000,
maximumAge: 2000,
enableHighAccuracy: true,
});
} else {
reject(new Error('Browser does not support geolocation!'));
}
});
promiseArray.push(getCurrentPositionPromise);
return Promise.race(promiseArray) as Promise<GeolocationPosition>;
}
standalone
, we're creating a promise that rejects
after 4 seconds (this value is arbitrary, the maximum time you want your users to wait) and pushing it to the promiseArray.promiseArray
as well.Promise.race()
. The key here is that there will only be one promise in the promiseArray
if the navigator is not standalone
, and will therefore work as intended. If the navigator is standalone, then there will be two promises in the promiseArray
and the Promise.race()
will reject from the timeout, thus rejecting from getUserPosition()
function.Upvotes: 4