Improve geolocation reliability: 3-stage fix with forgiving timeouts
Now that the native crash is fixed (Kotlin 2.1 alignment on the Android
side), the remaining issue was GPS "Location timed out" on a cold first
fix / indoors. Rework the native position acquisition into three
increasingly-forgiving stages that return the first success:
1. INSTANT — accept a cached/coarse fix up to 5 min old (resolves
immediately on a warm chip).
2. PRECISE — high-accuracy GPS with a generous 30s window so a cold
first-fix has room to complete.
3. COARSE FALLBACK — network/wifi fix with the longest window to
rescue the "GPS can't lock indoors" case.
Also bump the web-path timeout to 20s, and make the "Location timed out"
toast actionable on native (suggests stepping near a window / retrying).
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
This commit is contained in:
parent
71e5c5df1f
commit
9c7cd5ec4e
2 changed files with 41 additions and 17 deletions
|
|
@ -188,31 +188,53 @@ async function getNativePosition(native: CapGeolocationPlugin): Promise<GeoCoord
|
|||
throw new GeolocationError('denied', 'Location permission denied.');
|
||||
}
|
||||
|
||||
// First try a precise fix. High accuracy can fail/time out indoors or
|
||||
// with a weak GPS signal, which shows up as "unavailable" or "timeout".
|
||||
// Getting a location fix — especially a "cold start" the first time after
|
||||
// granting permission, or indoors — can be slow. A GPS chip can take 30s+
|
||||
// to acquire its first lock. So we try three increasingly-forgiving stages
|
||||
// and return the first one that succeeds. Each is guarded so a failure just
|
||||
// moves on to the next stage rather than surfacing as an error.
|
||||
|
||||
// Stage 1 — INSTANT: accept any recently cached fix (up to 5 min old).
|
||||
// enableHighAccuracy:false + short timeout means "give me a cached/coarse
|
||||
// fix immediately if you have one". This resolves instantly on a warm chip.
|
||||
try {
|
||||
const pos = await safeCall(() =>
|
||||
native.getCurrentPosition({
|
||||
enableHighAccuracy: false,
|
||||
timeout: 8000,
|
||||
maximumAge: 300000, // accept a fix up to 5 minutes old
|
||||
}),
|
||||
);
|
||||
return { lat: pos.coords.latitude, lng: pos.coords.longitude };
|
||||
} catch (cachedErr) {
|
||||
console.warn('[geolocation] cached/coarse fix unavailable, trying GPS:', cachedErr);
|
||||
}
|
||||
|
||||
// Stage 2 — PRECISE: full high-accuracy GPS with a generous window so a
|
||||
// cold first-fix has room to complete.
|
||||
try {
|
||||
const pos = await safeCall(() =>
|
||||
native.getCurrentPosition({
|
||||
enableHighAccuracy: true,
|
||||
timeout: 10000,
|
||||
maximumAge: 30000,
|
||||
timeout: 30000, // give a cold GPS lock plenty of time
|
||||
maximumAge: 60000,
|
||||
}),
|
||||
);
|
||||
return { lat: pos.coords.latitude, lng: pos.coords.longitude };
|
||||
} catch (highAccErr) {
|
||||
// Fall back to a coarse (network/cell/wifi) fix with a longer window.
|
||||
// This rescues the common "GPS can't lock" case that otherwise looks
|
||||
// like a hard failure.
|
||||
console.warn('[geolocation] high-accuracy failed, trying coarse:', highAccErr);
|
||||
const pos = await safeCall(() =>
|
||||
native.getCurrentPosition({
|
||||
enableHighAccuracy: false,
|
||||
timeout: 20000,
|
||||
maximumAge: 120000,
|
||||
}),
|
||||
);
|
||||
return { lat: pos.coords.latitude, lng: pos.coords.longitude };
|
||||
}
|
||||
|
||||
// Stage 3 — COARSE FALLBACK: network/cell/wifi fix with the longest window.
|
||||
// This rescues the common "GPS can't lock indoors" case.
|
||||
const pos = await safeCall(() =>
|
||||
native.getCurrentPosition({
|
||||
enableHighAccuracy: false,
|
||||
timeout: 30000,
|
||||
maximumAge: 300000,
|
||||
}),
|
||||
);
|
||||
return { lat: pos.coords.latitude, lng: pos.coords.longitude };
|
||||
} catch (err) {
|
||||
if (err instanceof GeolocationError) throw err;
|
||||
const msg = (err instanceof Error ? err.message : String(err)).toLowerCase();
|
||||
|
|
@ -255,7 +277,7 @@ function getWebPosition(): Promise<GeoCoords> {
|
|||
reject(new GeolocationError('unavailable', 'Location unavailable.'));
|
||||
}
|
||||
},
|
||||
{ enableHighAccuracy: true, timeout: 10000, maximumAge: 30000 },
|
||||
{ enableHighAccuracy: true, timeout: 20000, maximumAge: 60000 },
|
||||
);
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -656,7 +656,9 @@ export default function MapPage() {
|
|||
setNearMeError('timeout');
|
||||
toast({
|
||||
title: 'Location timed out',
|
||||
description: 'Could not get your location in time. Check your signal and try again.',
|
||||
description: isNativeGeolocation()
|
||||
? "Couldn't get a GPS fix in time. This is common on the first try or indoors — step near a window or outside and tap Near Me again."
|
||||
: 'Could not get your location in time. Check your signal and try again.',
|
||||
variant: 'destructive',
|
||||
});
|
||||
} else {
|
||||
|
|
|
|||
Loading…
Reference in a new issue