React Native 全栈开发实战班 - 原生功能集成之地理位置服务

news2024/11/18 8:14:52

地理位置服务 是移动应用中常见的功能之一,应用可以通过获取用户的地理位置信息提供个性化服务,如地图导航、附近商家推荐、实时位置跟踪等。React Native 提供了多种方式来实现地理位置服务,包括使用第三方库(如 react-native-geolocation-service)和调用原生模块。本章节将详细介绍如何使用 react-native-geolocation-service 库来实现地理位置服务,包括获取当前位置、监听位置变化、权限管理以及处理位置信息。


3.1 地理位置服务概述

地理位置服务主要涉及以下几个方面:

  1. 获取当前位置: 获取用户当前的地理位置信息,包括经度、纬度、海拔等。
  2. 监听位置变化: 实时监听用户的位置变化,适用于需要实时跟踪用户位置的场景。
  3. 地理围栏(Geofencing): 设置地理围栏,当用户进入或离开特定区域时触发相应的事件。
  4. 地图集成: 在应用中集成地图功能,显示用户位置、标记位置、绘制路线等。

React Native 提供了多种方式来实现地理位置服务:

  1. 第三方库:react-native-geolocation-service, react-native-location, react-native-maps 等,提供了封装好的 API,可以快速实现地理位置功能。
  2. 原生模块: 可以通过原生代码实现自定义地理位置功能,适用于需要高度定制化的场景。

本章节将重点介绍如何使用 react-native-geolocation-service 库来实现地理位置服务。


3.2 使用 react-native-geolocation-service

react-native-geolocation-service 是一个流行的第三方库,用于获取和监听地理位置信息,支持 iOS 和 Android 平台。

3.2.1 安装 react-native-geolocation-service
npm install react-native-geolocation-service

链接原生依赖(React Native 0.60 及以上版本自动链接):

cd ios
pod install
cd ..
3.2.2 配置权限

iOS:

Info.plist 文件中添加位置权限说明。

<key>NSLocationWhenInUseUsageDescription</key>
<string>需要访问您的位置以提供定位服务</string>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>需要始终访问您的位置以提供定位服务</string>
<key>NSLocationAlwaysUsageDescription</key>
<string>需要始终访问您的位置以提供定位服务</string>

Android:

AndroidManifest.xml 文件中添加位置权限。

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

注意: 对于 Android 6.0 及以上版本,还需要在代码中动态请求权限。

3.2.3 基本用法

获取当前位置:

import React, { useEffect, useState } from 'react';
import { View, Text, StyleSheet, Platform, Alert } from 'react-native';
import Geolocation from 'react-native-geolocation-service';

const LocationExample = () => {
  const [location, setLocation] = useState(null);

  const getLocation = () => {
    Geolocation.getCurrentPosition(
      (position) => {
        setLocation(position);
      },
      (error) => {
        console.error(error);
        Alert.alert('获取位置失败', error.message);
      },
      {
        enableHighAccuracy: true,
        timeout: 15000,
        maximumAge: 10000,
      }
    );
  };

  useEffect(() => {
    const requestLocationPermission = async () => {
      try {
        const granted = await Geolocation.requestPermission({
          androidPermission: {
            title: '位置权限',
            message: '应用需要访问您的位置以提供定位服务',
            buttonPositive: '确定',
            buttonNegative: '取消',
          },
          iosPermission: {
            title: '位置权限',
            message: '应用需要访问您的位置以提供定位服务',
            buttonPositive: '确定',
            buttonNegative: '取消',
          },
        });
        if (granted) {
          getLocation();
        } else {
          Alert.alert('权限被拒绝', '位置权限被拒绝,无法获取位置信息');
        }
      } catch (error) {
        console.error(error);
      }
    };

    requestLocationPermission();
  }, []);

  return (
    <View style={styles.container}>
      {location ? (
        <Text style={styles.text}>
          经度: {location.coords.longitude}, 纬度: {location.coords.latitude}
        </Text>
      ) : (
        <Text style={styles.text}>获取位置中...</Text>
      )}
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    padding: 20,
  },
  text: {
    fontSize: 18,
  },
});

export default LocationExample;

解释:

  • Geolocation.getCurrentPosition 方法: 获取当前位置信息。
  • enableHighAccuracy: 是否使用高精度模式。
  • timeout: 超时时间。
  • maximumAge: 缓存位置信息的最长时间。

监听位置变化:

import React, { useEffect, useState } from 'react';
import { View, Text, StyleSheet, Platform, Alert } from 'react-native';
import Geolocation from 'react-native-geolocation-service';

const WatchLocationExample = () => {
  const [location, setLocation] = useState(null);

  useEffect(() => {
    const watchId = Geolocation.watchPosition(
      (position) => {
        setLocation(position);
      },
      (error) => {
        console.error(error);
        Alert.alert('监听位置失败', error.message);
      },
      {
        enableHighAccuracy: true,
        distanceFilter: 10, // 位置变化距离阈值(米)
      }
    );

    return () => {
      Geolocation.clearWatch(watchId);
    };
  }, []);

  return (
    <View style={styles.container}>
      {location ? (
        <Text style={styles.text}>
          经度: {location.coords.longitude}, 纬度: {location.coords.latitude}
        </Text>
      ) : (
        <Text style={styles.text}>监听位置中...</Text>
      )}
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    padding: 20,
  },
  text: {
    fontSize: 18,
  },
});

export default WatchLocationExample;

解释:

  • Geolocation.watchPosition 方法: 监听位置变化。
  • distanceFilter: 位置变化距离阈值,只有位置变化超过该值时才会触发回调。
3.2.4 地理围栏

地理围栏(Geofencing) 是一种基于地理位置的服务,通过在地图上定义虚拟边界,当用户进入或离开特定区域时触发相应的事件。地理围栏广泛应用于各种场景,如:

  • 零售: 当用户接近商店时,发送促销信息或优惠券。
  • 物流: 跟踪车辆或货物是否进入或离开指定区域。
  • 安全: 监控用户是否进入或离开安全区域。
  • 社交: 提醒用户附近有朋友或活动。

在 React Native 中,可以通过 react-native-geolocation-service 库结合地理计算来实现简单的地理围栏功能。以下是详细的实现步骤和示例代码。

3.2.4.1 实现地理围栏

以下是一个简单的地理围栏实现示例,当用户进入或离开指定区域时,会弹出相应的提示。

import React, { useEffect, useState } from 'react';
import { View, Text, StyleSheet, Platform, Alert } from 'react-native';
import Geolocation from 'react-native-geolocation-service';

const GeofencingExample = () => {
  const [location, setLocation] = useState(null);
  const [geofence, setGeofence] = useState({
    latitude: 37.7749,  // 地理围栏中心纬度(例如:旧金山)
    longitude: -122.4194, // 地理围栏中心经度
    radius: 500, // 地理围栏半径(米)
  });

  useEffect(() => {
    const watchId = Geolocation.watchPosition(
      (position) => {
        setLocation(position);
        checkGeofence(position);
      },
      (error) => {
        console.error(error);
        Alert.alert('监听位置失败', error.message);
      },
      {
        enableHighAccuracy: true,
        distanceFilter: 10, // 位置变化距离阈值(米)
      }
    );

    return () => {
      Geolocation.clearWatch(watchId);
    };
  }, []);

  const checkGeofence = (position) => {
    const { latitude, longitude } = position.coords;
    const { latitude: fenceLat, longitude: fenceLng, radius } = geofence;

    // 计算两点之间的距离(使用 Haversine 公式)
    const distance = haversine(latitude, longitude, fenceLat, fenceLng);

    if (distance <= radius) {
      if (!geofence.inside) {
        setGeofence({ ...geofence, inside: true });
        Alert.alert('进入地理围栏', `已进入地理围栏区域,半径: ${radius}`);
      }
    } else {
      if (geofence.inside) {
        setGeofence({ ...geofence, inside: false });
        Alert.alert('离开地理围栏', `已离开地理围栏区域`);
      }
    }
  };

  // Haversine 公式计算两点之间的距离
  const haversine = (lat1, lon1, lat2, lon2) => {
    const R = 6371; // 地球半径,单位:公里
    const dLat = deg2rad(lat2 - lat1);
    const dLon = deg2rad(lon2 - lon1);
    const a =
      Math.sin(dLat / 2) * Math.sin(dLat / 2) +
      Math.cos(deg2rad(lat1)) * Math.cos(deg2rad(lat2)) *
      Math.sin(dLon / 2) * Math.sin(dLon / 2);
    const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
    const distance = R * c; // 距离,单位:公里
    return distance * 1000; // 转换为米
  };

  const deg2rad = (deg) => {
    return deg * (Math.PI / 180);
  };

  return (
    <View style={styles.container}>
      <Text style={styles.text}>当前位置:</Text>
      {location ? (
        <Text style={styles.text}>
          经度: {location.coords.longitude}, 纬度: {location.coords.latitude}
        </Text>
      ) : (
        <Text style={styles.text}>获取位置中...</Text>
      )}
      <Text style={styles.text}>地理围栏:</Text>
      <Text style={styles.text}>
        中心: 经度 {geofence.longitude}, 纬度 {geofence.latitude}, 半径 {geofence.radius}</Text>
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    padding: 20,
  },
  text: {
    fontSize: 18,
    marginVertical: 5,
  },
});

export default GeofencingExample;

解释:

  • 地理围栏定义:geofence 状态中定义地理围栏的中心坐标和半径。
  • 位置监听: 使用 Geolocation.watchPosition 监听用户的位置变化。
  • Haversine 公式: 计算当前位置与地理围栏中心之间的距离。
  • 进入/离开地理围栏: 当距离小于等于半径时,认为用户进入地理围栏;当距离大于半径时,认为用户离开地理围栏,并弹出相应的提示。

作者简介

前腾讯电子签的前端负责人,现 whentimes tech CTO,专注于前端技术的大咖一枚!一路走来,从小屏到大屏,从 Web 到移动,什么前端难题都见过。热衷于用技术打磨产品,带领团队把复杂的事情做到极简,体验做到极致。喜欢探索新技术,也爱分享一些实战经验,帮助大家少走弯路!

温馨提示:可搜老码小张公号联系导师

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2242696.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

GPU分布式通信技术-PCle、NVLink、NVSwitch深度解析

GPU分布式通信技术-PCle、NVLink、NVSwitch 大模型时代已到来&#xff0c;成为AI核心驱动力。然而&#xff0c;训练大模型却面临巨大挑战&#xff1a;庞大的GPU资源需求和漫长的学习过程。 要实现跨多个 GPU 的模型训练&#xff0c;需要使用分布式通信和 NVLink。此外&#xf…

基于 PyTorch 从零手搓一个GPT Transformer 对话大模型

一、从零手实现 GPT Transformer 模型架构 近年来&#xff0c;大模型的发展势头迅猛&#xff0c;成为了人工智能领域的研究热点。大模型以其强大的语言理解和生成能力&#xff0c;在自然语言处理、机器翻译、文本生成等多个领域取得了显著的成果。但这些都离不开其背后的核心架…

数据集的重要性:如何构建AIGC训练集

文章目录 一、为什么数据集对AIGC如此重要&#xff1f;1. 数据决定模型的知识边界2. 数据质量直接影响生成效果3. 数据集多样性提升模型鲁棒性 二、构建AIGC训练集的关键步骤1. 明确目标任务和生成需求2. 数据源的选择3. 数据清洗与预处理4. 数据标注5. 数据增强 三、针对不同类…

全网首发:Ubuntu编译跨平台嵌入式支持ffmpeg的OpenCV

难题&#xff1a; 使用cmake编译&#xff0c;死活找不到ffmpeg 使用cmake-gui&#xff0c;能找到ffmpeg&#xff0c;不能编译。 解决思路 结合cmake和cmake-gui。 为了给初次编译的朋友一点方便&#xff0c;这里专门完整详细记录。 安装编译环境 其他的略。 apt -y in…

算法——两两交换链表中的节点(leetcode24)

这是一道对于链表节点进行操作的题目非常考验对于链表操作的基本功&#xff1b; 解法: 本题的解法结合下图来进一步解释 创建一个虚拟节点指向头结点以便使代码逻辑看起来更为简便且操作节点容易,定义cur是为了方便找到cur之后的两个节点进行交换操作定义pre和aft是为了保存执…

非对称加密算法RSA的实现

一、实验目的 1、了解非对称密码体制基本原理 2、掌握编程语言实现非对称加密、解密 二、实验原理 RSA加密算法是一种非对称加密算法&#xff0c;所谓非对称&#xff0c;就是指该算法加密和解密使用不同的密钥&#xff0c;即使用加密密钥进行加密、解密密钥进行解密。在RAS…

劳动力市场

1.劳动力市场概述 &#xff08;1&#xff09;劳动力&#xff1a;所有有工作能力且愿意工作的人的总称&#xff0c;由那些正在工作&#xff08;就业&#xff09;和正在寻找工作&#xff08;失业&#xff09;的人组成&#xff0c;表示为&#xff1a;L&#xff08;劳动力&#xf…

拉取docker镜像应急方法

发现许多docker hub镜像网址速度也慢得发指啦&#xff0c;如果想速度快点&#xff0c;可以考虑买个按量计费的公有云服务器&#xff0c;用他们的内网镜像&#xff0c;然后再导出&#xff0c;然后传到本地。 开通服务器 可以考虑个开通最低配的&#xff0c;这里我用的是腾讯的…

go-zero(三) 数据库操作

go-zero 数据库操作 在本篇文章中&#xff0c;我们将实现一个用户注册和登录的服务。我们将为此构建一个简单而高效的 API&#xff0c;包括请求参数和响应参数的定义。 一、Mysql连接 1. 创建数据库和表 在 MySQL 中创建名为 test_zero的数据库&#xff0c;并创建user 表 …

113页PPT制造业研发工艺协同及制造一体化

研发工艺协同及制造一体化解决方案是制造业数字化转型的重要组成部分&#xff0c;它涵盖了从产品设计到生产的全过程&#xff0c;旨在提高生产效率、降低成本、提升产品质量&#xff0c;并增强企业的市场竞争力。以下是对该解决方案的详细阐述&#xff1a; 一、方案概述 研发…

【MySQL 保姆级教学】事务的隔离级别(详细)--下(14)

事务的隔离级别 1. 如何理解事务的隔离性2. 事务隔离级别的分类3. 查看和设置事务隔离级别3.1 全局和会话隔离级别3.2 查看和设置隔离级别 4. 事务隔离级别的演示4.1 读未提交&#xff08;Read Uncommitted&#xff09;4.2 读已提交&#xff08;Read Committed&#xff09;4.3 …

手机ip地址异常怎么解决

在现代社会中&#xff0c;手机已成为我们日常生活中不可或缺的一部分&#xff0c;无论是工作、学习还是娱乐&#xff0c;都离不开网络的支持。然而&#xff0c;有时我们会遇到手机IP地址异常的问题&#xff0c;这不仅会影响我们的网络体验&#xff0c;还可能带来安全隐患。本文…

STM32低功耗设计NFC与无线距离感应智能钥匙扣

目录 目录 前言 一、本设计主要实现哪些很“开门”功能&#xff1f; 二、电路设计原理图 1.电路图采用Altium Designer进行设计&#xff1a; 2.实物展示图片 三、程序源代码设计 四、获取资料内容 前言 在当今快速发展的物联网&#xff08;IoT&#xff09;时代&#xf…

Pyhon基础数据结构(列表)【蓝桥杯】

a [1,2,3,4,5] a.reverse() print("a ",a) a.reverse() print("a ",a)# 列表 列表&#xff08;list&#xff09;有由一系列按照特定顺序排序的元素组成 列表是有顺序的&#xff0c;访问任何元素需要通过“下标访问” 所谓“下标”就是指元素在列表从左…

关于win11电脑连接wifi的同时,开启热点供其它设备连接

背景&#xff1a; 我想要捕获手机流量&#xff0c;需要让手机连接上电脑的热点。那么问题来了&#xff0c;我是笔记本电脑&#xff0c;只能连接wifi上网&#xff0c;此时我的笔记本电脑还能开启热点供手机连接吗&#xff1f;可以。 上述内容&#xff0c;涉及到3台设备&#x…

SAP SD学习笔记13 - 出库确认(发货)之后的取消 - VL09

上一章讲了出荷传票的总结&#xff0c;以及出荷相关的其他知识&#xff0c;比如出荷控制&#xff0c;出荷传票登录的各种Tr-cd&#xff0c;Picking场所的决定&#xff0c;出荷传票的变更等内容。 SAP SD学习笔记12 - 出荷传票总结&#xff0c;出荷控制(出荷Type&#xff0c;出…

IDEA优雅debug

目录 引言一、断点分类&#x1f384;1.1 行断点1.2 方法断点1.3 属性断点1.4 异常断点1.5 条件断点1.6 源断点1.7 多线程断点1.8 Stream断点 二、调试动作✨三、Debug高级技巧&#x1f389;3.1 watch3.2 设置变量3.3 异常抛出3.4 监控JVM堆大小3.5 数组过滤和筛选 引言 使用ID…

MyBatisPlus(Spring Boot版)的基本使用

1. 初始化项目 1.1. 配置application.yml spring:# 配置数据源信息datasource:# 配置数据源类型type: com.zaxxer.hikari.HikariDataSource# 配置连接数据库信息driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/mybatis_plus?characterEncodi…

串口DMA接收不定长数据

STM32F767—&#xff1e;串口通信接收不定长数据的处理方法_stm32串口超时中断-CSDN博客 STM32-HAL库串口DMA空闲中断的正确使用方式解析SBUS信号_stm32 hal usart2 dma-CSDN博客 #define USART1_RxBuffSize 100 extern DMA_HandleTypeDef hdma_usart1_rx; //此处声明的变量在…

【Linux】进程字段、环境变量与进程地址空间

&#x1f308; 个人主页&#xff1a;谁在夜里看海. &#x1f525; 个人专栏&#xff1a;《C系列》《Linux系列》《算法系列》 ⛰️ 丢掉幻想&#xff0c;准备斗争 目录 一、查看进程字段 1.字段说明 2.进程优先级 二、环境变量 1.概念 2.指令与PATH 3.环境变…