被一个问题不间断折磨了一周,今天终于有了眉目。
问题描述:一个工单系统,该系统可以支持网络协议切换,http,或者https的都行。然后利用工单链接,在移动端进行工单的处理。
问题:定位
比较坑的是:这个位置定位
// 获取当前经纬度,是否支持定位功能?
async getCurrentLocation() {
if (navigator.geolocation) {
await navigator.geolocation.getCurrentPosition(position => {
let {longitude, latitude } = position.coords;
this.lng = longitude;
this.lat = latitude;
this.switchLnglatRegion();
}, err => {
console.log('定位发生错误', err);
}, {
enableHighAccuracy: true,
timeout: 8000, //如果在8秒钟之内还没有得到用户信息,报出错误超时的错误
maximumAge: 3000 // 最长有效期,在重复获取地理位置时,此参数指定多久再次获取位置。
}
);
} else {
this.toast = this.$createToast({
// Fixme: 交互没有该情况下交互文本
txt: '当前浏览器不支持自动定位功能',
type: 'warn',
time: 2000
});
this.toast.show();
}
},
http协议下:
原因:
首先想到的是排查机型问题。由于客户多为IOS用户,所以最先看的是在安卓是有没有此问题的发生,调查结果为安卓没有任何问题。再排查IOS的版本问题,结果发现无法获取地理位置的为IOS10版本,而IOS9上同样无此现象的产生。
所以基本定位到是IOS 10版本可能对我们现在的代码没法兼容,没办法小胳膊弄不过大腿,所以我们再定位现在的代码是通过什么样的方式去获取地理位置的。
基本可以确定IOS 10可能对H5获取地理位置的API做了限制或者有了修改,具体什么修改还需要继续排查。
在网上google了一下,原来这个问题在IOS10推出就已存在,现在已经到了10.3+了我们才暴露出来,蜜汁尴尬。。
具体的原因也说的比较明白:
在IOS 10中,苹果对webkit定位权限进行了修改,所有定位请求的页面必须是https协议的。
如果是非https网页,在http协议下通过html5原生定位接口会返回错误,
也就是无法正常定位到用户的具体位置,而已经支持https的网站则不会受影响。
解决方案:
基本网上有两种解决方案:
1、将网站的http设置为Https。
2、通过第三方解决,即通过调用百度地图或者腾讯地图来获取地理位置
我也想着使用第三方解决,但是我在使用百度API去获取地理位置的时候发现和真实的经纬度又有所偏差,原来百度地图对地理位置又进行了二次加密,又是一个坑,果断放弃(而且我们是国际产品,产品中已经引入了谷歌地图,在他喵引入国内地图,肯定不合适)。
而第一个方案,升级网站为https是个长期规划的过程(鬼才知道有多少个坑在里面),所以就需要找一个比较能短时间解决问题的方案。
最后终于在犄角旮旯找到了基本的解决方案:采用iframe可以绕过IOS的这一限制(但是没法绕过谷歌浏览器的限制)
var options = {
enableHighAccuracy: true,
maximumAge: 30000,
timeout: 12000
};
window.locationCallback = function(err, position) {
if (err) {
window.showError(err);
return;
}
window.showPosition(position);
};
var str = '<iframe src="javascript:(function(){ '
+ 'window.navigator.geolocation.getCurrentPosition('
+ 'function(position){parent && parent.locationCallback && parent.locationCallback(null,position);}, '
+ 'function(err){parent && parent.locationCallback && parent.locationCallback(err);}, '
+ '{enableHighAccuracy : ' + options.enableHighAccuracy + ', maximumAge : ' + options.maximumAge + ', timeout :' + options.timeout + '})'
+ ';})()" style="display:none;"></iframe>';
$(str).appendTo('body');
window.showPosition = function(position) {
// TODO
console.log('position', position);
};
window.showError = function(error) {
switch (error.code) {
case error.PERMISSION_DENIED:
alert('用户不允许地理定位!');
break;
case error.POSITION_UNAVAILABLE:
alert('无法获取当前位置!');
break;
case error.TIMEOUT:
alert('操作超时!');
break;
case error.UNKNOWN_ERROR:
alert('未知错误!');
break;
default:
break;
}
};
iframe解决是2017年的方案,现在是2022年,使用以上浏览器警告,好了路彻底堵死。
VM22653:1[弃用]getCurrentPosition()和watchPosition()不再在不安全的源上工作。
要使用此特性,您应该考虑将应用程序切换到安全源,例如HTTPS。 详见https://goo.gl/rStTGz。
解决方案:
一个思维很重要,国际产品,国际思路解决,用个锤子的百度,直接chrome搜索,最终方案:
谷歌地图官方说明链接
// 协议 post请求无入参:
https://www.googleapis.com/geolocation/v1/geolocate?key=谷歌key值
// 结果
{
"location": {
"lat": 35.86166,
"lng": 104.195397
},
"accuracy": 1804475.2390180232
}
另一种解决方案:
function do_something(coords) {
// Do something with the coords here
}
navigator.geolocation.getCurrentPosition(function(position) {
do_something(position.coords);
},
function(failure) {
$.getJSON('https://ipinfo.io/geo', function(response) {
var loc = response.loc.split(',');
var coords = {
latitude: loc[0],
longitude: loc[1]
};
do_something(coords);
});
};
});
其余的解决方案就不行了,是修改浏览器设置的,很明显,不可取