Chrome V105+离线环境下PWA无法调用Geolocation API获取GPS坐标
我用React+JavaScript开发了一个PWA,需要在无网络环境下仅通过Android平板的GPS模块获取坐标。权限已经授予,代码在Chrome V104及以下版本运行正常,但从V105开始,离线时无法获取坐标,Geolocation API的回调函数完全被忽略,既不触发成功回调也不触发错误回调。
相关代码实现
location.js
module.exports = class Location { constructor() { this.ready = 'geolocation' in navigator this.id = null } get() { return new Promise((resolve, reject) => { if (!this.ready) return reject(new Error('no geolocation in navigator')) navigator.geolocation.getCurrentPosition( (position) => { const coord = { lat: position.coords.latitude, lng: position.coords.longitude, alt: position.coords.altitude } return resolve(coord) }, (error) => { return reject(error) } ) }) } watch(resolve, reject) { const options = { maximumAge: 5 * 60 * 1000 // 5 minutes is the maximum age of a possible cached position that is acceptable to return } this.id = navigator.geolocation.watchPosition( (position) => { const coord = { lat: position.coords.latitude, lng: position.coords.longitude, alt: position.coords.altitude } return resolve(coord) }, (error) => { return reject(error) }, options ) } clean() { if (this.id === null) return navigator.geolocation.clearWatch(this.id) } }
Shell.js中调用定位函数(componentDidMount)
async componentDidMount () { try { const position = await location.get() log.info(`location.get() returns ${JSON.stringify(position)}`) } catch (error) { log.error('location.get() errors', error) } location.watch( (position) => { // Decrease alt precision if (position.alt) position.alt = parseInt(position.alt) // A GPS fix has already been made if (this.state.position !== null) { function equalTo5(a, b) { return a.toFixed(5) === b.toFixed(5) } const sameLat = equalTo5(this.state.position.lat, position.lat) const sameLng = equalTo5(this.state.position.lng, position.lng) if (sameLat && sameLng) return server.setPosition(position) this.setState({position}) } else { log.info(`GPS reading ${JSON.stringify(position)}`) server.setPosition(position) this.setState({position}) } }, (error) => { if (error.message.startsWith('Only secure origins are allowed')) { const position = {lat: 13, lng: 37, alt: 1337} log.info(`GPS fake reading ${JSON.stringify(position)}`) this.setState({position}) return } log.error('GPS cannot get location', error) if (this.state.position === null) this.setState({positionError: error}) }) this.getServiceWorkerRegistration() }
补充说明
- 已确认代码未被弃用、函数签名正确,查阅Chrome发布说明未发现相关定位获取逻辑或要求的变更;
- Android设备已设置为仅使用GPS定位,平板连接的是无互联网访问权限的设备内置WiFi网络;
- 测试覆盖Android 8、11系统及Chrome V70(仅Android8)、V90、V104至V108版本。
问题原因及解决方案
核心原因
Chrome V105开始调整了离线环境下Geolocation API的行为:当设备连接到无互联网的WiFi网络时,Chrome会默认认为当前网络环境不可靠,进而限制了纯GPS定位的获取逻辑,导致回调函数完全不触发——这是因为Chrome在V105+中新增了网络可用性校验逻辑,即使设备仅设置GPS定位,只要连接了无网WiFi,就会触发这个限制,跳过GPS模块的调用。
解决方案
强制启用高精度定位
在调用getCurrentPosition和watchPosition时,必须显式设置enableHighAccuracy: true,这个参数会强制Chrome优先调用硬件GPS模块,忽略网络可用性的校验。修改代码如下:在
location.js的get方法中添加参数:navigator.geolocation.getCurrentPosition( (position) => { /* 现有成功逻辑 */ }, (error) => { /* 现有错误逻辑 */ }, { enableHighAccuracy: true } // 新增参数 )在
watch方法的options中添加参数:const options = { maximumAge: 5 * 60 * 1000, enableHighAccuracy: true // 新增参数 }
添加超时机制避免静默阻塞
部分Android设备在Chrome V105+中,即使开启高精度定位,首次GPS定位仍可能存在较长延迟,建议在watchPosition的options中添加timeout参数,确保超时后能触发错误回调,避免回调完全静默:const options = { maximumAge: 5 * 60 * 1000, enableHighAccuracy: true, timeout: 30000 // 30秒超时 }适配网络状态判断
若必须保留无网WiFi连接,可在调用定位API前通过navigator.onLine判断网络状态,若离线则明确告知用户当前依赖硬件GPS定位,减少用户困惑。
版本差异说明
Chrome V104及之前版本中,enableHighAccuracy参数默认会优先使用GPS,即使连接无网WiFi也不会触发网络校验逻辑;而V105开始,Chrome优化了定位策略,默认情况下会依赖网络辅助定位,当网络不可用时直接跳过GPS调用,必须显式开启enableHighAccuracy才能强制使用硬件GPS。
内容的提问来源于stack exchange,提问作者jordanlepera

