React Native高德地图SDK插件分析
-
react-native-smart-amap
这个库比较完美实现了地图选址功能,但是作者好像不再维护了,所以慎用。 -
react-native-amap3d
这个库做的比较好,功能比较齐全,但是经过分析后,很难实现我们想要的功能。而且作者也建议使用网页实现此类功能。 -
react-native-amap-geolocation
react-native-amap3d 作者将定位功能抽出来,针对的是使用高德地图进行高精度定位。感谢作者!
实现思路
- 根据react-native-amap3d作者的建议,我们使用网页实现主体界面。
- 使用react-native-amap-geolocation进行高精度定位
申请高德地图key
- 在高德地图管理控制台申请Android、iOS和web端key。
web端实现
- 使用高德地图选址组件,请按照高德地图说明申请web端key
- 添加本地html代码
- map.html
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black" />
<title>地理位置</title>
<style>
body{
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
margin: 0;
}
iframe{
width: 99%;
height: 98%;
}
</style>
</head>
<body>
<iframe id="container" src=''></iframe>
<script>
(function(){
var iframe = document.getElementById('container').contentWindow;
document.getElementById('container').onload = function(){
iframe.postMessage('hello','https://m.amap.com/picker/');
};
window.addEventListener("message", function(e){
window.postMessage(JSON.stringify({
name: e.data.name,
location: e.data.location,
address: e.data.address
}))
}, false);
}())
</script>
</body>
</html>
- 需要注意的一点就是,由于React-Native WebView加载本地html文件问题,map.html文件需要分两个目录进行存放,iOS可以直接放在项目任何目录下(如:项目根目录)引用即可,而android必须放在android assets文件下才可以引用。
- 使用window.postMessage() 将位置选取信息回传给WebView
-
如图:
android文件存储目录
React Native端实现
- 使用react-native-amap-geolocation进行精准定位。自行参考文档。
// 获取定位权限,由于我写界面的时候,还需要其他权限,这边我使用的是多权限申请方式,定位的单个申请是没问题的。如果觉得别扭,可以自行修改。
async componentDidMount () {
await init({
ios: IOS_MAP_KEY, // iOS key
android: ANDROID_MAP_KEY // android key
})
if (!IS_IOS) {
try {
const permissions = [
PermissionsAndroid.PERMISSIONS.ACCESS_COARSE_LOCATION
]
// 返回得是对象类型
const granteds = await PermissionsAndroid.requestMultiple(permissions)
if (granteds['android.permission.ACCESS_COARSE_LOCATION'] !== 'granted') {
ToastAndroid.show('请开通定位权限,否则应用定位功能无法正常使用!', ToastAndroid.SHORT)
} else {
this.getCurrentPosition()
}
} catch (e) {
ToastAndroid.show('定位权限获取异常', ToastAndroid.SHORT)
}
} else {
this.getCurrentPosition()
}
}
// 获取定位信息
getCurrentPosition () {
Geolocation.getCurrentPosition(({ location }) => {
this.setState({
lat: location.latitude,
lng: Math.abs(location.longitude), // 国内获取的是一个负值。这里需要注意一下,是否考虑使用{lng:-location.longitude} 请自行验证
positionGetError: false
})
}, () => {
this.setState({
positionGetError: true
})
}, {
timeout: 8
})
}
- 使用WebView加载网页
// WEB_CLIENT web端key值
<WebView
bounces={false}
domStorageEnabled={false}
javaScriptEnabled
useWebKit
injectedJavaScript={`document.getElementById("container").src="https://m.amap.com/picker/?center=${this.state.lng},${this.state.lat}&zoom=18&key=${WEB_CLIENT}&keywords=景区,超市,小区"`}
onMessage={(e) => {
console.log('data', e.nativeEvent.data)
}}
mixedContentMode={'always'}
renderError={() => this._renderWebViewError()}
source={IS_IOS ? require('../htmls/map.html') : { uri: 'file:///android_asset/htmls/map.html' }}
/>
- 注意:添加useWebKit,否则iOS可能会出现问题
- 从代码中我们可以看出,我们使用injectedJavaScript对web端注入了一段javascript代码,目的是将我们的位置信息注入,并且改变web端iframe的src地址。
- onMessage获取web端postMessage()的回传数据
网友评论