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

Expo应用生产环境授权位置权限后崩溃问题求助

Expo生产环境授权位置权限后应用崩溃(开发环境正常)

以下是针对该问题的常见排查方向和解决方案:

  • 权限配置不完整
    生产环境构建的应用需要在app.json/app.config.js中明确声明位置权限,Expo Go开发环境会自动处理权限,但正式包必须显式配置。检查expo.android.permissions数组,确保包含ACCESS_FINE_LOCATION和ACCESS_COARSE_LOCATION:

    "android": {
      "permissions": [
        "ACCESS_FINE_LOCATION",
        "ACCESS_COARSE_LOCATION"
      ]
    }
    
  • 位置请求的异步逻辑异常
    生产环境中设备的位置服务可能存在延迟或不可用,getCurrentPositionAsync默认配置可能导致超时未处理引发崩溃。修改请求配置,增加超时限制并降低精度要求:

    const location = await Location.getCurrentPositionAsync({
      timeout: 5000,
      enableHighAccuracy: false,
      maximumAge: 10000
    });
    
  • 空值强制解包风险
    代码中permissionDenied分支里使用currentLocation!强制解包,如果setDefaultLocationOnMap因异常未正确设置currentLocation,生产环境会触发空值崩溃。替换强制解包为安全判断:

    {currentLocation && (
      <MapView
        style={styles.map}
        initialRegion={currentLocation}
        onPress={handlePress}
      >
        {marker && <Marker coordinate={marker}/>}
      </MapView>
    )}
    
  • SDK版本兼容性问题
    确认expo-location、react-native-maps与当前Expo SDK版本兼容,部分版本在生产构建中存在API行为差异。运行expo install expo-location react-native-maps确保依赖版本匹配,重新构建生产包。

  • 添加崩溃日志收集
    集成Expo Crashlytics捕获生产环境崩溃日志,具体崩溃栈信息能快速定位问题:

    expo install expo-crashlytics
    

原组件代码

import React, {useState, useEffect} from 'react';
import {View, StyleSheet, Dimensions} from 'react-native';
import MapView, {Marker, Region} from 'react-native-maps';
import * as Location from 'expo-location';
import Loader from "../Loader";

interface LocationPickerProps {
    onLocationSelect?: (location: { latitude: number; longitude: number }) => void;
    selectedLocation?: { latitude: number; longitude: number } | null;
}

const LocationPicker = ({onLocationSelect, selectedLocation}: LocationPickerProps) => {
    const [currentLocation, setCurrentLocation] = useState<Region | null>(null);
    const [marker, setMarker] = useState<{ latitude: number; longitude: number } | null>(null);
    const [isLoading, setIsLoading] = useState(true);
    const [permissionDenied, setPermissionDenied] = useState(false);

    // Effect for requesting location permission and handling location update
    useEffect(() => {
        const requestLocationPermission = async () => {
            try {
                setIsLoading(true);
                const {status} = await Location.requestForegroundPermissionsAsync();
                console.log("STATUS", status);
                if (status !== 'granted') {
                    setPermissionDenied(true);
                    setDefaultLocationOnMap();
                    return;
                }

                // If permissions are granted, fetch the location
                fetchLocation();
            } catch (error) {
                // console.error('Error requesting location permission:', error);
                setDefaultLocationOnMap();
            } finally {
                setIsLoading(false);
            }
        };

        requestLocationPermission();
    }, []);

    // Function to fetch and update location
    const fetchLocation = async () => {
        try {
            if (selectedLocation) {
                const region: Region = {
                    latitude: selectedLocation.latitude,
                    longitude: selectedLocation.longitude,
                    latitudeDelta: 0.01,
                    longitudeDelta: 0.01,
                };
                setCurrentLocation(region);
                setMarker(selectedLocation);
            } else {
                const location = await Location.getCurrentPositionAsync({});
                if (location && location.coords) {
                    const {latitude, longitude} = location.coords;
                    const region: Region = {
                        latitude,
                        longitude,
                        latitudeDelta: 0.01,
                        longitudeDelta: 0.01,
                    };
                    setCurrentLocation(region);
                    setMarker({latitude, longitude});
                    if (onLocationSelect) {
                        onLocationSelect({latitude, longitude})
                    }
                } else {
                    setDefaultLocationOnMap();
                }
            }
        } catch (error) {
            // console.error('Error getting location:', error);
            setDefaultLocationOnMap();
        }
    };

    const setDefaultLocationOnMap = () => {
        const defaultLocation: Region = {
            latitude: 0,
            longitude: 0,
            latitudeDelta: 0.01,
            longitudeDelta: 0.01,
        };
        setCurrentLocation(defaultLocation);
    };

    const handlePress = (event: any) => {
        const coordinate = event.nativeEvent.coordinate;
        setMarker(coordinate);
        if (onLocationSelect) {
            onLocationSelect(coordinate);
        }
    };

    if (isLoading) {
        return (
            <View style={styles.loadingContainer}>
                <Loader/>
            </View>
        );
    }

    if (permissionDenied) {
        return (
            <View style={styles.container}>
                <MapView
                    style={styles.map}
                    initialRegion={currentLocation!}
                    onPress={handlePress}
                >
                    {marker && <Marker coordinate={marker}/>}
                </MapView>
            </View>
        );
    }

    return (
        <View style={styles.container}>
            {currentLocation && (
                <MapView
                    style={styles.map}
                    initialRegion={currentLocation}
                    onPress={handlePress}
                >
                    {marker && <Marker coordinate={marker}/>}
                </MapView>
            )}
        </View>
    );
};

const styles = StyleSheet.create({
    container: {
        flex: 1,
        justifyContent: 'center',
        alignItems: 'center',
    },
    map: {
        width: Dimensions.get('window').width,
        flex: 1,
    },
    loadingContainer: {
        flex: 1,
        justifyContent: 'center',
        alignItems: 'center',
    },
});

export default LocationPicker;

内容的提问来源于stack exchange,提问作者user2426691

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 01:40:56