需求
获取客户地址,帮助客户回填地址信息,节省客户的操作,提升用户体验。
解决
拿到这个需求,我就去RN官网找了一波,看看有没有现成的API,Ctrl+C,Ctrl+V操作一波。
的确找到了 React Native Geolocation,跟着上面的操作一波就ok了。
注意一定要配好权限。
这里说下要注意的几个点
1. 在Android上要申请获取地址权限
如果 Android 设备 API 版本>=18(即 Android 4.3 及以上),则位置信息还会包含额外的布尔值
mocked
,表示此位置信息可能由某服务模拟得出。
如果 Android 设备 API 版本>=18(即 Android 6.0 及以上),则需要额外的步骤来检查权限,即使用PermissionsAndroid API
来检查 ACCESS_FINE_LOCATION 权限。 不这么做的话可能导致应用崩溃闪退。
首先,要请求访问地理位置的权限,你需要在AndroidManifest.xml文件中加入如下一行:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
其次,在你的页面加上这个判断
if(Platform.OS == 'ios'){
this.getPosition();
}else{
const permissions = [
PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION,
]
const granteds = await PermissionsAndroid.requestMultiple(permissions);
if (granteds["android.permission.ACCESS_FINE_LOCATION"] === "granted") {
this.getPosition();
} else {
Toast.info("定位权限被禁止")
}
}
上面的代码,getPosition函数就是获取地址的函数。我们这边要先判断平台,如果是IOS,就直接获取地址就可以,如果是Android,就必须判断是否有权限。
2. 关于getCurrentPosition()方法和watchPosition()
为什么要说这两个函数呢,因为我们项目里遇到一个问题。
最开始,我用的是getCurrentPosition,但是我们客户进入认证页面,获取到了地址,然后退出页面,到其他地方,再打开认证页面,发现获取的地址还是上一个地点,说明根本取到的是缓存。【吐槽一下,我在真机和模拟器上都能看到进入页面有重新获取地址,但是就是不准确,不知道为何,本以为是设置了缓存,但是查看了一下,代码里根本没设置maximumAge 这个字段,所以目前也不清楚啥原因】
所以我就换了watchPosition,持续监听位置变化,就解决了这个问题。
3. 关于定位不准确
就在我解决了上面那个问题,兴高采烈的打包给我们的测试,结果测试马上就拿着几个测试机过来打我脸(:з」∠)。说是定位不准确,差距太大,而且位置描述太模糊,没精确到楼层,只定位到大致的街道。。。
如果有看官网geolocation那篇文章的小伙伴,肯定看到最开始,官网就提示了:
本 API 在安卓上需要谷歌框架支持,因而无法在国内使用,请在 github 上搜索百度或高德等国内第三方封装替代库。
地理定位只用于返回经纬度数据,无法得出具体地名。如果需要通过经纬度数据查询具体地名,则需要额外的“逆地理编码”(即通过经纬度查询地图数据库得到地名)。一般第三方的地图封装带有此功能。
所以我用的是高德地图来逆地理编码返回我所需要的地址。
但是
为啥会不精准呢!打开高德官网搜索了一波。找到原因,原来是要转换坐标,把非高德坐标转换成高德坐标 高德 坐标转换。这样就能把地址精确了一些,emmmmmm,至少精确到了手机附近的地点,不再只是附近的街道。
相关链接
高德地理/逆地理编码api:
https://lbs.amap.com/api/webservice/guide/api/georegeo/
高德坐标转换api:
https://lbs.amap.com/api/webservice/guide/api/convert/
React Native Geolocation 【这个链接上面有完整权限配置和代码】
https://aboutreact.com/react-native-geolocation/
getposition函数完整代码
以下代码是直接copy网上一片博客的代码,因为我的getposition函数的高德逆地理编码是在后台进行的,有些出入,所以直接网上找了个差不多的,而且很完整的。
不过他用的是getCurrentPosition方法。这个看自己需求改吧。
如果和我一样用的是watchPosition方法,一定要记得在生命周期componentWillUnmount函数内clearWatch。这个官网有说明,但是容易被忽略。
getPositions=()=>{
//获取位置再得到城市先后顺序,通过Promise完成
return new Promise((resolve, reject) => {
Geolocation.getCurrentPosition(
location => {
this.setState({
longitude: location.coords.longitude,//经度
latitude: location.coords.latitude,//纬度
});
fetch(`https://restapi.amap.com/v3/assistant/coordinate/convert?locations=${this.state.longitude},${this.state.latitude}&coordsys=gps&output=json&key=${config.GaoDeKey.key}`, { method: "GET" })
.then(response => response.json())
.then((jsonDa) => {
let newVar = jsonDa.locations.split(',')
this.setState({
longitude: newVar[0],//经度
latitude: newVar[1],//纬度
});
//访问网络开始
fetch('http://restapi.amap.com/v3/geocode/regeo?key='+config.GaoDeKey.key+'&location='+this.state.longitude+','+this.state.latitude+'&radius=1000&extensions=all&batch=false&roadlevel=0', {
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded"
},
body: ``
})
.then((response) => response.json())
.then((jsonData) => {
try {
//Toast.show(jsonData.result.formatted_address+jsonData.result.sematic_description)
this.setState({
position:jsonData.regeocode.formatted_address,
});
}catch (e) {
}
})
.catch((error) => {
console.error(error);
});
//访问网络结束
})
.catch(error => {
reject(error);
});
},
error => {
reject(error);
if(error.code==2){
ToastAndroid.show('定位失败,请查看手机是否开启GPS定位服务',ToastAndroid.SHORT);
}else if(error.code==3){
ToastAndroid.show("定位超时,请尝试重新获取定位",ToastAndroid.SHORT);
}else{
ToastAndroid.show("定位失败:"+error.message,ToastAndroid.SHORT);
}
}, {
enableHighAccuracy: false,
timeout: 5000,
maximumAge: 10000
}
);
})
}
---------------------
作者:迷途的羔羊_
来源:CSDN
原文:https://blog.csdn.net/Destiny_strive/article/details/86059800
版权声明:本文为博主原创文章,转载请附上博文链接!