You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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}`
        );
    }
});

错误原因分析

  1. JSON语法错误:infoPlist配置中NSLocationAlwaysUsageDescription末尾缺少逗号,导致整个infoPlist无法被正确解析,Expo无法将这些配置注入到Info.plist中,因此系统检测不到权限描述和后台模式配置。
  2. 未处理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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 23:55:54