如何在React Native CLI中获取用户城市位置并适配Expo代码
React Native CLI 迁移:获取用户城市并发送至后端方案
一、安装必要依赖
React Native CLI没有Expo内置的定位和存储工具,需要安装以下第三方库:
- 存储工具:
npm install @react-native-async-storage/async-storage - 定位服务:
npm install react-native-geolocation-service - 权限管理:
npm install react-native-permissions - (可选)逆地理编码库:
npm install react-native-geocoding(也可直接调用谷歌API)
二、配置安卓权限
在android/app/src/main/AndroidManifest.xml中添加定位权限声明:
<!-- 基础定位权限 --> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
三、完整代码实现
以下代码对应原Expo逻辑,替换了CLI不支持的API:
import React, { useState, useEffect, useCallback } from 'react'; import AsyncStorage from '@react-native-async-storage/async-storage'; import Geolocation from 'react-native-geolocation-service'; import { PermissionsAndroid, Alert } from 'react-native'; // 若使用react-native-geocoding,需先初始化(替换为你的谷歌API密钥) // import Geocoder from 'react-native-geocoding'; // Geocoder.init('YOUR_GOOGLE_MAPS_API_KEY'); const App = () => { const [userdata, setUserdata] = useState(null); const [location, setLocation] = useState(null); const [errorMsg, setErrorMsg] = useState(null); const [city, setCity] = useState(null); useEffect(() => { getUserData(); getLocation(); }, []); const getUserData = useCallback(async () => { try { const userDataString = await AsyncStorage.getItem('user'); const userData = JSON.parse(userDataString); setUserdata(userData); } catch (err) { Alert.alert('读取用户数据失败', err.message); } }, []); // 请求定位权限 const requestLocationPermission = async () => { try { const granted = await PermissionsAndroid.request( PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION, { title: '请求定位权限', message: '应用需要获取您的位置以确定所在城市', buttonPositive: '允许', buttonNegative: '取消', } ); return granted === PermissionsAndroid.RESULTS.GRANTED; } catch (err) { console.warn('权限请求出错:', err); return false; } }; const getLocation = useCallback(async () => { const hasPermission = await requestLocationPermission(); if (!hasPermission) { setErrorMsg('定位权限已拒绝'); return; } // 获取当前位置 Geolocation.getCurrentPosition( async (position) => { setLocation(position); // 逆地理编码获取城市名称(二选一) // 方法1:使用react-native-geocoding库 // try { // const result = await Geocoder.from(position.coords.latitude, position.coords.longitude); // const cityComponent = result.results[0].address_components.find(item => item.types.includes('locality')); // setCity(cityComponent?.long_name); // } catch (err) { // console.error('逆地理编码失败:', err); // } // 方法2:直接调用谷歌Geocoding API(无需额外依赖) try { const apiKey = 'YOUR_GOOGLE_MAPS_API_KEY'; const response = await fetch( `https://maps.googleapis.com/maps/api/geocode/json?latlng=${position.coords.latitude},${position.coords.longitude}&key=${apiKey}` ); const data = await response.json(); if (data.status === 'OK') { const cityComponent = data.results[0].address_components.find(item => item.types.includes('locality')); setCity(cityComponent?.long_name); } else { console.error('地理编码API返回错误:', data.status); } } catch (err) { console.error('调用地理编码API失败:', err); } }, (error) => { console.error('获取位置失败:', error); setErrorMsg('无法获取当前位置'); }, { enableHighAccuracy: true, timeout: 15000, maximumAge: 10000 } ); }, []); const sendCity = useCallback(async () => { if (!userdata || !city) return; try { const response = await fetch('https://backnedurl.com/GetCity', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ city: city, username: userdata.user.username }), }); const data = await response.json(); console.log('城市信息发送成功:', data); } catch (err) { console.error('发送城市信息失败:', err); } }, [userdata, city]); useEffect(() => { sendCity(); }, [userdata, city, sendCity]); // 调试:打印所有存储的键值对 useEffect(() => { const logAllStorageItems = async () => { try { const keys = await AsyncStorage.getAllKeys(); for (const key of keys) { const value = await AsyncStorage.getItem(key); console.log(`${key}: ${value}`); } } catch (error) { console.log('读取存储键值失败:', error); } }; logAllStorageItems(); }, []); return ( // 你的组件内容 null ); }; export default App;
核心差异说明
- AsyncStorage替换:Expo的内置
AsyncStorage已废弃,CLI使用@react-native-async-storage/async-storage,API调用方式基本一致。 - 定位服务替换:Expo的
Location模块替换为react-native-geolocation-service,需手动处理权限请求。 - 逆地理编码:Expo内置的
reverseGeocodeAsync无官方替代,需通过谷歌Geocoding API或第三方库实现,注意需要申请谷歌地图API密钥并启用Geocoding服务。 - 权限处理:CLI中需通过
PermissionsAndroid手动构建权限弹窗,而非Expo封装好的权限请求方法。
内容的提问来源于stack exchange,提问作者Code
相关产品推荐
相关产品推荐

