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

如何在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;

核心差异说明

  1. AsyncStorage替换:Expo的内置AsyncStorage已废弃,CLI使用@react-native-async-storage/async-storage,API调用方式基本一致。
  2. 定位服务替换:Expo的Location模块替换为react-native-geolocation-service,需手动处理权限请求。
  3. 逆地理编码:Expo内置的reverseGeocodeAsync无官方替代,需通过谷歌Geocoding API或第三方库实现,注意需要申请谷歌地图API密钥并启用Geocoding服务。
  4. 权限处理:CLI中需通过PermissionsAndroid手动构建权限弹窗,而非Expo封装好的权限请求方法。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 16:55:22