預(yù)覽
React Native高德地圖SDK插件分析
-
react-native-smart-amap
這個庫比較完美實現(xiàn)了地圖選址功能,但是作者好像不再維護了,所以慎用。 -
react-native-amap3d
這個庫做的比較好,功能比較齊全,但是經(jīng)過分析后,很難實現(xiàn)我們想要的功能。而且作者也建議使用網(wǎng)頁實現(xiàn)此類功能。 -
react-native-amap-geolocation
react-native-amap3d 作者將定位功能抽出來,針對的是使用高德地圖進行高精度定位。感謝作者!
實現(xiàn)思路
- 根據(jù)react-native-amap3d作者的建議,我們使用網(wǎng)頁實現(xiàn)主體界面。
- 使用react-native-amap-geolocation進行高精度定位
申請高德地圖key
- 在高德地圖管理控制臺申請Android、iOS和web端key。
web端實現(xiàn)
- 使用高德地圖選址組件,請按照高德地圖說明申請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端實現(xiàn)
- 使用react-native-amap-geolocation進行精準(zhǔn)定位。自行參考文檔。
// 獲取定位權(quán)限,由于我寫界面的時候,還需要其他權(quán)限,這邊我使用的是多權(quán)限申請方式,定位的單個申請是沒問題的。如果覺得別扭,可以自行修改。
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('請開通定位權(quán)限,否則應(yīng)用定位功能無法正常使用!', ToastAndroid.SHORT)
} else {
this.getCurrentPosition()
}
} catch (e) {
ToastAndroid.show('定位權(quán)限獲取異常', ToastAndroid.SHORT)
}
} else {
this.getCurrentPosition()
}
}
// 獲取定位信息
getCurrentPosition () {
Geolocation.getCurrentPosition(({ location }) => {
this.setState({
lat: location.latitude,
lng: Math.abs(location.longitude), // 國內(nèi)獲取的是一個負值。這里需要注意一下,是否考慮使用{lng:-location.longitude} 請自行驗證
positionGetError: false
})
}, () => {
this.setState({
positionGetError: true
})
}, {
timeout: 8
})
}
- 使用WebView加載網(wǎng)頁
// 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=景區(qū),超市,小區(qū)"`}
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可能會出現(xiàn)問題
- 從代碼中我們可以看出,我們使用injectedJavaScript對web端注入了一段javascript代碼,目的是將我們的位置信息注入,并且改變web端iframe的src地址。
- onMessage獲取web端postMessage()的回傳數(shù)據(jù)