React Native使用react-native-geolocation-service时watchPosition不更新问题
问题根因与修复方案
一、现有代码的核心问题
watchPosition未做权限校验就直接调用:你把位置权限校验逻辑都封装在hasLocationPermission里,但useEffect初始化监听的时候完全没有先校验权限,大概率首次初始化时权限还没授予,监听器本身就没生效useEffect缺少依赖数组且没有清理逻辑:没有传空依赖数组的话,每次组件重渲染都会重复创建新的位置监听器,既会导致回调重复触发,也会出现监听器泄漏的问题;同时没有在组件卸载时调用clearWatch清理监听器,也会引发异常watchPosition未传配置参数:你给getCurrentPosition传了高精度、1米触发阈值的配置,但watchPosition用的是默认配置,默认的distanceFilter(位置变化最小触发距离)通常是100米,你模拟器修改的位置如果移动距离小于这个阈值就不会触发回调,精度配置不够也会导致模拟位置不被识别
二、修复后的代码示例
import * as React from 'react'; import { useState, useEffect, Platform, PermissionsAndroid, ToastAndroid, Alert, View, TouchableOpacity, Text } from 'react-native'; import Geolocation from 'react-native-geolocation-service'; export default function TestScreen () { // 存储监听器ID,用于卸载时清理 const [watchId, setWatchId] = useState(null); const hasLocationPermission = async () => { if (Platform.OS === 'android' && Platform.Version < 23) { return true; } const hasPermission = await PermissionsAndroid.check( PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION, ); if (hasPermission) { return true; } const status = await PermissionsAndroid.request( PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION, ); if (status === PermissionsAndroid.RESULTS.GRANTED) { return true; } if (status === PermissionsAndroid.RESULTS.DENIED) { ToastAndroid.show( 'Location permission denied by user.', ToastAndroid.LONG, ); } else if (status === PermissionsAndroid.RESULTS.NEVER_ASK_AGAIN) { ToastAndroid.show( 'Location permission revoked by user.', ToastAndroid.LONG, ); } return false; }; // 初始化位置监听 const initWatch = async () => { const hasPermission = await hasLocationPermission(); if (!hasPermission || watchId) return; const id = Geolocation.watchPosition((position) => { console.log('位置更新:', position); }, (error) => { console.log('监听错误:', error); }, { // 和getCurrentPosition用相同的高精度配置 accuracy: { android: 'high', ios: 'best', }, distanceFilter: 1, // 位置变化1米就触发回调 interval: 1000, // 安卓端位置更新最小间隔1秒 fastestInterval: 500, }); setWatchId(id); }; useEffect(() => { initWatch(); // 组件卸载时清理监听器 return () => { if (watchId) { Geolocation.clearWatch(watchId); } }; }, []); // 空依赖数组,只在组件首次挂载时初始化一次 const getLocation = async () => { const hasPermission = await hasLocationPermission(); if (!hasPermission) { return; } Geolocation.getCurrentPosition( (position) => { console.log('手动获取位置:', position); }, (error) => { Alert.alert(`Code ${error.code}`, error.message); console.log(error); }, { accuracy: { android: 'high', ios: 'best', }, timeout: 15000, maximumAge: 10000, distanceFilter: 1, }, ); }; return ( <View> <TouchableOpacity onPress={ () => getLocation() }> <Text>Hello there!</Text> </TouchableOpacity> </View> ); };
三、额外校验项
如果修改后还是不触发模拟位置更新,检查以下配置:
- 安卓模拟器:确认扩展控制面板的位置设置里,
Speed不是0,修改位置后点击Set Location按钮生效 - 权限配置:安卓12及以上版本需要在
AndroidManifest.xml里额外添加ACCESS_COARSE_LOCATION、ACCESS_FINE_LOCATION权限,如果要后台监听还要加ACCESS_BACKGROUND_LOCATION - 模拟器位置模式:不要选择固定位置模式,改成连续模拟或者每次修改后手动触发位置更新
内容的提问来源于stack exchange,提问作者knownothingjonsnow
相关产品推荐
相关产品推荐

