使用Expo Location获取后台定位权限时遇配置错误求助
前后台位置追踪配置错误排查与解决
问题场景
使用expo-location和expo-task-manager实现应用前后台位置获取功能,通过Expo编译代码(未使用Xcode),运行时触发两个未处理的Promise拒绝错误。
错误日志
[Unhandled promise rejection: Error: One of the `NSLocation*UsageDescription` keys must be present in Info.plist to be able to use geolocation.] at node_modules\@babel\runtime\helpers\construct.js:null in <global> at node_modules\@babel\runtime\helpers\wrapNativeSuper.js:null in _wrapNativeSuper - ... 3 more stack frames from framework internals
[Unhandled promise rejection: Error: Background Location has not been configured. To enable it, add `location` to `UIBackgroundModes` in Info.plist file.] at node_modules\@babel\runtime\helpers\construct.js:null in <global> at node_modules\@babel\runtime\helpers\wrapNativeSuper.js:null in _wrapNativeSuper - ... 3 more stack frames from framework internals
当前App.json的infoPlist配置
"infoPlist": { "UIBackgroundModes": ["location"], "NSLocationWhenInUseUsageDescription": "To allow the user to start recording a run...", "NSLocationAlwaysUsageDescription": "To allow the distance to be measured even when the phone is turned off" "NSLocationAlwaysAndWhenInUseUsageDescription": "Allow $(PRODUCT_NAME) to use your location to track your runs" }
相关代码
App.js
import React, { useState, useEffect } from 'react'; import { View, Text, StyleSheet } from 'react-native'; import UserLocation from "./UserLocation" export default function App() { return ( <View style={styles.container}> <UserLocation /> </View> ); } const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: '#fff', alignItems: 'center', justifyContent: 'center', }, });
UserLocation.js
import React from 'react'; import { View, Text, TouchableOpacity, StyleSheet } from 'react-native'; import * as Location from 'expo-location'; import * as TaskManager from 'expo-task-manager'; const LOCATION_TRACKING = 'location-tracking'; var l1; var l2; export default function UserLocation() { const [locationStarted, setLocationStarted] = React.useState(false); const startLocationTracking = async () => { await Location.startLocationUpdatesAsync(LOCATION_TRACKING, { accuracy: Location.Accuracy.Highest, timeInterval: 5000, distanceInterval: 0, }); const hasStarted = await Location.hasStartedLocationUpdatesAsync( LOCATION_TRACKING ); setLocationStarted(hasStarted); console.log('tracking started?', hasStarted); }; React.useEffect(() => { const config = async () => { let resf = await Location.requestForegroundPermissionsAsync(); let resb = await Location.requestBackgroundPermissionsAsync(); if (resf.status != 'granted' && resb.status !== 'granted') { console.log('Permission to access location was denied'); } else { console.log('Permission to access location granted'); } }; config(); }, []); const startLocation = () => { startLocationTracking(); } const stopLocation = () => { setLocationStarted(false); TaskManager.isTaskRegisteredAsync(LOCATION_TRACKING) .then((tracking) => { if (tracking) { Location.stopLocationUpdatesAsync(LOCATION_TRACKING); } }) } return ( <View> {locationStarted ? <TouchableOpacity onPress={stopLocation}> <Text style={styles.btnText}>Stop Tracking</Text> </TouchableOpacity> : <TouchableOpacity onPress={startLocation}> <Text style={styles.btnText}>Start Tracking</Text> </TouchableOpacity> } </View> ); } const styles = StyleSheet.create({ btnText: { fontSize: 20, backgroundColor: 'green', color: 'white', paddingHorizontal: 30, paddingVertical: 10, borderRadius: 5, marginTop: 10, }, }); TaskManager.defineTask(LOCATION_TRACKING, async ({ data, error }) => { if (error) { console.log('LOCATION_TRACKING task ERROR:', error); return; } if (data) { const { locations } = data; let lat = locations[0].coords.latitude; let long = locations[0].coords.longitude; l1 = lat; l2 = long; console.log( `${new Date(Date.now()).toLocaleString()}: ${lat},${long}` ); } });
错误原因分析
- JSON语法错误:
infoPlist配置中NSLocationAlwaysUsageDescription末尾缺少逗号,导致整个infoPlist无法被正确解析,Expo无法将这些配置注入到Info.plist中,因此系统检测不到权限描述和后台模式配置。 - 未处理Promise拒绝:异步操作(如权限请求、位置更新启动)未用
try/catch包裹,导致错误直接抛出成为未处理的Promise拒绝。
解决方案
1. 修复App.json的JSON语法错误
修改后的infoPlist配置(添加缺失的逗号):
"infoPlist": { "UIBackgroundModes": ["location"], "NSLocationWhenInUseUsageDescription": "To allow the user to start recording a run...", "NSLocationAlwaysUsageDescription": "To allow the distance to be measured even when the phone is turned off", "NSLocationAlwaysAndWhenInUseUsageDescription": "Allow $(PRODUCT_NAME) to use your location to track your runs" }
2. 清理Expo缓存并重启项目
执行以下命令清除缓存后重新运行:
expo r -c
3. 优化异步操作的错误处理
修改startLocationTracking和权限请求逻辑,添加try/catch捕获错误:
// 权限请求逻辑优化 React.useEffect(() => { const config = async () => { try { let resf = await Location.requestForegroundPermissionsAsync(); if (resf.status !== 'granted') { console.log('Foreground location permission denied'); return; } let resb = await Location.requestBackgroundPermissionsAsync(); if (resb.status !== 'granted') { console.log('Background location permission denied'); } else { console.log('All location permissions granted'); } } catch (err) { console.error('Permission request error:', err); } }; config(); }, []); // 启动位置追踪逻辑优化 const startLocationTracking = async () => { try { await Location.startLocationUpdatesAsync(LOCATION_TRACKING, { accuracy: Location.Accuracy.Highest, timeInterval: 5000, distanceInterval: 0, }); const hasStarted = await Location.hasStartedLocationUpdatesAsync(LOCATION_TRACKING); setLocationStarted(hasStarted); console.log('tracking started?', hasStarted); } catch (err) { console.error('Failed to start location tracking:', err); setLocationStarted(false); } };
4. 停止追踪逻辑添加错误处理
const stopLocation = () => { setLocationStarted(false); TaskManager.isTaskRegisteredAsync(LOCATION_TRACKING) .then((tracking) => { if (tracking) { return Location.stopLocationUpdatesAsync(LOCATION_TRACKING); } }) .catch(err => console.error('Failed to stop location tracking:', err)); }
内容的提问来源于stack exchange,提问作者Saw
相关产品推荐
相关产品推荐

