升级至Expo SDK 51后React Native Maps使用PROVIDER_DEFAULT崩溃
Expo SDK 51升级后React Native Maps异常排查与解决
问题描述
升级Expo SDK 51后,React Native Maps出现两处异常:
- 使用
PROVIDER_DEFAULT时应用直接崩溃 - 使用
PROVIDER_GOOGLE时iOS端抛出错误:ERROR react-native-maps: AirGoogleMaps dir must be added to your xCode project to support GoogleMaps on iOS.
项目中结合BottomSheetModal实现地图内搜索功能,核心代码片段如下:
var mapStyle = [ { "elementType": "geometry", "stylers": [ { "color": "#f5f5f5" } ] }, // 省略其余地图样式配置 { "featureType": "water", "elementType": "labels.text.fill", "stylers": [ { "color": "#9e9e9e" } ] } ] //SetLocation Modal state const [searchLocationModal, setSearchLocationModal] = useState(false); const [isLoading, setIsLoading] = useState(false); //geoLocation state const { userLocation } = useSnapshot(locationState); const DELTA_VALUE = 0.005 const initialRegion = { latitude: locationState.latitude, longitude: locationState.longitude, latitudeDelta: 0.005, longitudeDelta: 0.005, } const [markerLocation, setMarkerLocation] = useState({ latitude: locationState.latitude, longitude: locationState.longitude, latitudeDelta: DELTA_VALUE, longitudeDelta: DELTA_VALUE, }) const sheetRef = useRef<BottomSheet>(null) //Second SnapPoint 45% const snapPoints = ['38%', '38%'] const [addressSearch, setAddressSearch] = useState(''); const updateLocation = async () => { let currentUserID = firebase.default.auth().currentUser?.uid try { if(currentUserID){ await updateUser(currentUserID).then((doc) => { //Check if markerLocation is the same as saved LatLng doc.get().then((userDoc) => { if (markerLocation.latitude != userDoc.data().location.lat && markerLocation.longitude != userDoc.data().location.long ){ doc.update({ "location.lat": markerLocation.latitude, "location.long": markerLocation.longitude, }).then(async () => { await getSavedLocation().then(() => {setSearchLocationModal(false)}) }) } else { console.log('Location is the same') } }).then(() => { findNearestPopular() }) }) } else { locationState.latitude = markerLocation.latitude locationState.longitude = markerLocation.longitude await getAddress({lat: markerLocation.latitude, long: markerLocation.longitude}).then(() => { setSearchLocationModal(false) console.log(locationState) }).then(() => { findNearestPopular() }) } } catch (error) { console.log(error.message) } } useEffect(() => { const timer = setTimeout(() => { if(addressSearch == ''){ setMarkerLocation(initialRegion) } else getLatLang(addressSearch).then((x) => { console.log('Bottom Sheet result: ' + x?.lat, x?.long) if (x?.lat && x?.long != undefined) { setMarkerLocation({ latitude: x?.lat, longitude: x?.long, latitudeDelta: DELTA_VALUE, longitudeDelta: DELTA_VALUE }) } }) },500) return () => {clearTimeout(timer)} }, [locationState, addressSearch]) return ( <> <Modal animationType="slide" visible={searchLocationModal} onRequestClose={() => { setSearchLocationModal(!searchLocationModal); }} > <TouchableOpacity style={styles.modalCloseBtn} onPress={() => {setSearchLocationModal(!searchLocationModal)}}> <Entypo name="chevron-small-left" size={30} color="#37BD6B"/> </TouchableOpacity> <MapView.Animated style={{height: '70%', width: '100%', zIndex: -1}} mapType={"standard"} provider={PROVIDER_DEFAULT} initialRegion={initialRegion} region={markerLocation} customMapStyle={mapStyle} > <Marker.Animated coordinate={markerLocation}></Marker.Animated> </MapView.Animated> <BottomSheet keyboardBehavior="interactive" ref={sheetRef} snapPoints={snapPoints} style={{}}> <React.Fragment> <View style={styles.currentLocationContainer}> <View> <MaterialIcons style={styles.locationIcon} name={'my-location'} size={25}/> </View> <View style={styles.currentLocationTxtGrp}> <View> <Text style={{fontWeight: '700', fontSize: 18, fontFamily: 'Gilroy-SemiBold', marginBottom: 4}}>Current Location</Text> </View> <View> <Text style={{fontWeight: '400', fontSize: 16, fontFamily: 'Gilroy-Medium'}}>{userLocation}</Text> </View> </View> </View> <View style={styles.searchContainer}> <View style={styles.searchIconContainer}> <AntDesign style={{paddingLeft: 15, color: "#B3B4B9"}} name="search1" size={19} /> </View> <BottomSheetTextInput onChangeText={(value) => setAddressSearch(value)} style={styles.searchBar}/> </View> <TouchableOpacity onPress={updateLocation} > <View style={styles.updateLocationContainer}> <Text style={styles.updateLocation}>Update Location</Text> </View> </TouchableOpacity> </React.Fragment> </BottomSheet> </Modal> )
解决方案
一、修复PROVIDER_DEFAULT崩溃问题
- 适配依赖版本:Expo SDK 51对应React Native 0.74,需安装适配的react-native-maps版本(建议
^1.14.0及以上):
npx expo install react-native-maps@latest
- 配置位置权限:在
app.json/app.config.js中补充位置权限声明:
{ "expo": { "ios": { "infoPlist": { "NSLocationWhenInUseUsageDescription": "需要访问您的位置以显示地图" } }, "android": { "permissions": ["ACCESS_FINE_LOCATION", "ACCESS_COARSE_LOCATION"] } } }
- 清除缓存重建:
npx expo prebuild --clean npx expo run:ios npx expo run:android
二、解决Google Maps iOS端报错问题
Expo managed workflow下无法手动操作Xcode项目添加AirGoogleMaps目录,推荐使用官方适配的expo-google-maps:
- 安装依赖:
npx expo install expo-google-maps
- 替换组件导入:将原react-native-maps的MapView替换为expo-google-maps的组件:
// 移除旧导入 // import MapView, { Marker } from 'react-native-maps'; import { MapView, Marker } from 'expo-google-maps';
- 配置API密钥:在
app.json中添加Google Maps API密钥:
{ "expo": { "ios": { "googleMapsApiKey": "你的iOS端Google Maps API密钥" }, "android": { "googleMapsApiKey": "你的Android端Google Maps API密钥" } } }
三、额外注意事项
- 若必须使用原生react-native-maps的Google Maps provider,需切换到bare workflow,手动在Xcode中添加
react-native-maps包内的AirGoogleMaps目录,并配置API密钥。 - 检查BottomSheet与MapView的层级:确保
zIndex设置合理,避免交互冲突或视图遮挡。
内容的提问来源于stack exchange,提问作者CodingJunkie
相关产品推荐
相关产品推荐

