Skip to content

Commit 57e545c

Browse files
committed
fix: replace getCurrentPosition with watchPosition for iOS Safari
iOS Safari re-prompts geolocation permission on every getCurrentPosition call after a page reload. Replace the getCurrentPosition + setInterval pattern with watchPosition which triggers only one permission prompt and continuously delivers updates. Also guard navigator.permissions.query() which is unsupported on iOS Safari, and add error callbacks for permission denied, position unavailable, and timeout scenarios.
1 parent 266050d commit 57e545c

2 files changed

Lines changed: 40 additions & 30 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## Unreleased
99

10+
- Fix iOS Safari geolocation re-prompting on every page reload (use `watchPosition`, guard `permissions.query`)
1011
- Security and dependency updates (8 vulnerabilities fixed, ESLint v9, React/Prettier updated)
1112

1213
## [1.0.8] - 2025-28-01

src/App.jsx

Lines changed: 39 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ function App() {
2828
const [infoText, setInfoText] = useState("");
2929
const [lat, setLat] = useState(null);
3030
const [long, setLong] = useState(null);
31-
const locationUpdateInterval = 30000;
3231

3332
const contextLatLong = useMemo(
3433
() => ({
@@ -38,42 +37,52 @@ function App() {
3837
[lat, long],
3938
);
4039

41-
function handlePermissionInfoBanner() {
42-
navigator.permissions.query({ name: "geolocation" }).then((result) => {
43-
if (result.state !== "granted") {
44-
setInfo(true);
45-
setInfoText(
46-
<span>
47-
Du har ikke accepteret, at vi må få adgang til din lokation. For at denne applikation skal fungere, skal den
48-
bruge din lokation. Hvis du vil vide mere om hvordan du giver denne angang, kan du besøge{" "}
49-
<Link className="underline" to="/navigation-help">
50-
Hjælp til navigation
51-
</Link>
52-
</span>,
53-
);
54-
}
55-
});
56-
}
40+
const permissionDeniedBanner = (
41+
<span>
42+
Du har ikke accepteret, at vi må få adgang til din lokation. For at denne applikation skal fungere, skal den bruge
43+
din lokation. Hvis du vil vide mere om hvordan du giver denne adgang, kan du besøge{" "}
44+
<Link className="underline" to="/navigation-help">
45+
Hjælp til navigation
46+
</Link>
47+
</span>
48+
);
5749

5850
useEffect(() => {
59-
handlePermissionInfoBanner();
51+
if (navigator.permissions && navigator.permissions.query) {
52+
navigator.permissions
53+
.query({ name: "geolocation" })
54+
.then((result) => {
55+
if (result.state === "denied") {
56+
setInfo(true);
57+
setInfoText(permissionDeniedBanner);
58+
}
59+
})
60+
.catch(() => {});
61+
}
6062
}, []);
6163

62-
function startLocationPrompter() {
63-
setInterval(() => {
64-
navigator.geolocation.getCurrentPosition((position) => {
64+
useEffect(() => {
65+
const watchId = navigator.geolocation.watchPosition(
66+
(position) => {
6567
setLat(position.coords.latitude);
6668
setLong(position.coords.longitude);
67-
});
68-
}, locationUpdateInterval);
69-
}
69+
},
70+
(err) => {
71+
if (err.code === err.PERMISSION_DENIED) {
72+
setInfo(true);
73+
setInfoText(permissionDeniedBanner);
74+
} else if (err.code === err.POSITION_UNAVAILABLE) {
75+
setError(true);
76+
setErrorText("Din lokation kunne ikke bestemmes.");
77+
} else if (err.code === err.TIMEOUT) {
78+
setError(true);
79+
setErrorText("Forespørgslen om din lokation tog for lang tid.");
80+
}
81+
},
82+
{ enableHighAccuracy: true, timeout: 30000, maximumAge: 10000 },
83+
);
7084

71-
useEffect(() => {
72-
navigator.geolocation.getCurrentPosition((position) => {
73-
setLat(position.coords.latitude);
74-
setLong(position.coords.longitude);
75-
});
76-
startLocationPrompter();
85+
return () => navigator.geolocation.clearWatch(watchId);
7786
}, []);
7887

7988
useEffect(() => {

0 commit comments

Comments
 (0)