基于React-Native做位置信息获取
在这个里面最重要的是两个部分,一个是位置定位的权限获取,一个是实时位置的监听,在安卓项目中,在
android/app/src/main/AndroidManifest.xml
该文件下,在< manifest > 标签内写入以下权限
<!--用于访问GPS定位-->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<!--用于进行网络定位-->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.INTERNET" />
获取当前位置信息,在React-Native项目中,我使用的WebView来做地图渲染,基于openlayer提前将vue3+vite工程构建好,将打包的项目放置在
android/app/src/main/assets/GIS
在React-Native页面内代码如下
import React, {useEffect, useRef, useState} from 'react';
import {View, StyleSheet, PermissionsAndroid, Alert} from 'react-native';
import Geolocation from '@react-native-community/geolocation';
import {WebView} from 'react-native-webview';
import {useFocusEffect} from '@react-navigation/native';
// 获取设备地理位置
let watchId;
const MyWebView = () => {
const [error, setError] = useState(null);
const webViewRef = useRef(null);
// 请求位置权限
const requestLocationPermission = async () => {
try {
const granted = await PermissionsAndroid.request(
PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION,
{
title: 'Location Permission',
message: 'App needs access to your location.',
buttonPositive: 'OK',
},
);
if (granted === PermissionsAndroid.RESULTS.GRANTED) {
console.log('Location permission granted');
// 用户已授予位置权限,开始获取地理位置
getDeviceLocation();
// startLocationWatch(); // 调用开始位置监视函数
} else {
console.log('Location permission denied');
// 处理权限被拒绝的情况
Alert.alert(
'Location Permission Denied',
'Please enable location services to use this feature.',
);
}
} catch (err) {
console.warn(err);
}
};
const getDeviceLocation = () => {
watchId = Geolocation.watchPosition(
position => {
const {latitude, longitude, heading} = position.coords;
// 向 WebView 发送位置数据,但只有在WebView加载完成后才发送
// if (webViewLoaded) {
const locationData = JSON.stringify({longitude, latitude, heading});
// webViewRef.current.injectJavaScript(jsCode);
webViewRef.current?.injectJavaScript(`
function toChangeLocation(){
window.currentLocation = '${locationData}';
// 手动触发位置变化事件,通知监听器
const event = new Event('currentLocationChanged');
event.detail = window.currentLocation; // 通过事件的 detail 属性传递新的位置信息
window.dispatchEvent(event);
}
setInterval(()=>{
toChangeLocation()
},500)
`);
},
error => {
setError(error.message);
},
{
enableHighAccuracy: true,
timeout: 20000,
maximumAge: 1000,
accuracy: {
android: 'high',
ios: 'best',
},
distanceFilter: -1,
interval: 1000,
},
);
return () => {
Geolocation.clearWatch(watchId);
watchId = undefined;
};
};
// 在屏幕聚焦时执行
useFocusEffect(
React.useCallback(() => {
watchId && Geolocation.clearWatch(watchId);
watchId = undefined;
requestLocationPermission();
getDeviceLocation();
return () => {
clearLocationWatch();
};
}, []),
);
// 清除位置监视
const clearLocationWatch = () => {
watchId && Geolocation.clearWatch(watchId);
};
return (
<View style={styles.container}>
<WebView
ref={webViewRef}
source={{uri: 'file:///android_asset/GIS/index.html'}} // 这里的路径应该指向你的Vue.js项目的index.html文件
// source={{uri: `http://192.168.87.184:5173`}} // 要加载的外部链接地址
style={styles.webview}
javaScriptEnabled={true}
scalesPageToFit={true}
mixedContentMode="always"
useWebKit={true}
startInLoadingState={true}
/>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
},
webview: {
flex: 1,
},
});
export default MyWebView;
模拟器内更改位置是立即执行的,但是到手机里面就只执行一次了,所以我给了interval,具体原因位置,另外本来项目与webview通信应该用postmessage通信,但是打完包后,挂在window下的function拿不到,具体原因还不清楚,所以只能在项目中强制监听了,然后在html中自己写事件去触发自己,在项目中
window.addEventListener('currentLocationChanged', (event) => {
let newLocation = event.detail; // 获取新的位置信息
updateMapLocation(newLocation); // 调用更新地图位置的函数
if(firstLocate){
firstLocate=false
locateToCurrent()
}
});