当前位置: 首页 > news >正文

iOS中的定位实现(逆地理编码)及Info.plist位置权限详解

引言

在现代移动应用开发中,位置服务已经成为不可或缺的一部分。无论是地图导航、社交分享,还是基于位置的个性化推荐,位置数据都为用户提供了更加丰富和智能的体验。然而,随着用户隐私保护的不断加强,iOS对位置权限的管控也变得越来越严格。这使得开发者在使用位置服务时需要更加谨慎,合理地选择合适的权限请求,确保符合隐私政策的同时提供良好的用户体验。

在本篇博客中,我们将深入探讨如何在iOS中选择合适的定位权限,并介绍如何实现一下几种常见的定位需求:

  • 如何选择合适的定位权限。
  • 如何进行单次定位获取。
  • 如何实现持续定位。
  • 如何进行逆地理编码,获取具体的地理信息。

希望通过本篇博客,能够帮助大家更好地理解iOS中的定位服务,并在实际开发中得心应手地运用它们。

权限配置

在iOS开发中所有的权限申请都需要再Info.pilst文件中进行声明,并填写描述来说明为什么你的应用要访问用户的这个权限。这些描述信息回在用户请求权限时显示给他们,帮助他们理解应用申请权限的意图,关于定位权限Info.plist文件给我们提供了很多选项,接下来我们就一一来解释一下:

1. Privacy - Location Always and When in Use Usage Description

  • 字段名称:NSLocationAlwaysAndWhenInUseUsageDescription
  • 权限用途:这个描述字段用于当你的应用需要请求“始终定位”权限时,解释为什么需要在前台和后台都访问位置权限。
  • 显示位置:当我们发起locationAlwaysAndWhenInUse的权限请求时,系统会自动展示这段描述给用户。

2. Privacy - Location Always Usage Description

  • 字段名称:NSLocationAlwaysUsageDescription
  • 权限用途:这个描述字段也用于“始终定位”权限的申请。
  • 显示位置:当应用请求locationAlways权限时,就会显示我们在该字段中设置的描述,主要用于请求后台定位权限。

3. Privacy - Locaion Default Accuracy Reduced

  • 字段名称:NSLocationDefaultAccuracyReducedUsageDescription
  • 权限用途:这个描述字段是用于减少定位精度时显示的提示,主要为了告知用户应用正在使用较低精度的定位,也就是粗略的位置信息。
  • 显示位置:当应用的权限被限定为“粗略定位”(locationAccuracyReduced)时,这个描述会被展示。用户可以选择仅允许粗略位置权限来保护隐私。

4.Privacy - Location Temporary Usage Description

  • 字段名称:NSLocationTemporaryUsageDescription
  • 权限用途:这个描述字段是用于临时的定位权限请求。例如,某些场景应用可能会请求一次性 的定位权限,或者在某些特定的操作中需要访问用户的临时权限。
  • 显示位置:当应用只需要临时使用位置是,iOS会显示此描述,通常适用于单次定位。

5. Privacy - Lcation Usage Description

  • 字段名称:NSLocationUsageDescription
  • 权限用途:这是一个比较通用的定位权限描述字段,可以用于任何请求位置权限的场景。它用于描述应用需要位置权限的基本原因,通常情况下我们会将其用在“使用期间定位”权限(locationWhenUse)。
  • 显示位置:当应用请求locationWhenUse权限时,会提示此描述。

6. Privacy - Location When in Use Usage Description

  • 字段名称:NSLocationWhenInUseUsageDescription
  • 权限用途:用于请求“使用期间定位”权限的描述字符。
  • 显示位置:当应用请求locationWhenInUse权限时,这个字段的内容会展示给用户。

这些字段的主要作用就是让用户知道引用为什么要使用对应的权限。我们需要根据应用的需要来配置Info.plist文件。

请求定位

在iOS应用中发起定位需要使用CoreLocation框架下的CLLocationManager来进行,在使用CLLocationManager的对象进行定位之前,首先我们需要确保Info.plist文件中已经创建了我们需要申请权限的描述字段。否则控制台的log会提示你需要申请对应权限。

单次定位

如果你的应用不需要在后台进行定位,那么我们可以选择NSLocationWhenInUseUsageDescription字段,在使用期间进行定位。

我们创建一个名为MWLocationHelper的类,负责定位功能。首选需要引入CoreLocation框架,并创建一个CLLocationManager的实例,设置代理及定位精度等信息:

import CoreLocationpublic class MWLocationHelper: NSObject, CLLocationManagerDelegate {....public override init() {super.init()initLocationManager()}private func initLocationManager() {locationManager = CLLocationManager()locationManager.delegate = selflocationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeterslocationManager.distanceFilter = 100}....
}

当我们需要请求应用的位置信息时,比较通用的做法顺序是:

  1. 检查用户位置权限。
  2. 请求用户位置权限。
  3. 开启定位。

首先我们来检查用户的位置权限,如果用户已经授权,那么我们可以直接进行定位请求,如果用户尚未授权位置权限,我们可以发起权限请求。但是如果用户已经拒绝了权限的申请,我们则需要使用自定义的弹窗和内容来引导用户到设置页中修改权限。

    /// 开始定位public func startLocation() {self.checkLocationPermission()}/// 检查权限private func checkLocationPermission() {let status = CLLocationManager.authorizationStatus()switch status {case .notDetermined:// 如果还没请求过权限,则请求权限locationManager.requestWhenInUseAuthorization()case .restricted, .denied:// 如果被拒绝或受限,提示用户MWToast.showToast("请打开定位服务")MWLogHelper.info("请打开定位服务1",context: "MWLocationHelper")case .authorizedAlways, .authorizedWhenInUse:// 如果已经授权,则可以开始定位locationManager.requestLocation()@unknown default:break}}

CLLocationManagerDelegate协议有三个可选方法需要我们来实现,分别是权限发生变化的回调方法,定位成功的回调方法以及定位失败的回调方法。

当权限发生变更时,系统会自定调用下面方法,在该方法里,我们可以根据权限状态进行处理,如果用户已经授权,则直接开启定位,否则提示用户授权失败或者其它业务操作:

    /// 权限public func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {switch status {case .authorizedWhenInUse, .authorizedAlways:// 授权通过,开始更新位置locationManager.requestLocation()case .denied, .restricted:// 授权失败,提示用户MWToast.showToast("请打开定位服务")MWLogHelper.info("请打开定位服务2",context: "MWLocationHelper")default:break}}

当定位成功之后,会进入另外一个代理方法,我们可以在该方法中获取用户的位置信息如经度纬度,并通过代理或者闭包将数据回调出去。

    /// CLLocationManagerDelegatepublic func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {if let location = locations.last {let latitude = location.coordinate.latitudelet longitude = location.coordinate.longitudeself.longitude = longitudeself.latitude = latitudeMWLogHelper.info("定位成功 \(longitude) \(latitude)",context: "MWLocationHelper")// 主线程回调didUpdateLocation?(longitude, latitude)reverseGeocodeLocation(location: location)}}

如果定位失败则会进入另外一个方法,在这里我们可以进行提示或者其他业务操作:

    public func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {MWToast.showToast("定位失败")MWLogHelper.info("定位失败",context: "MWLocationHelper")}

持续定位

如果需要持续定位,我们需要使用startUpdatingLocation方法进行定位,也就是将locationManager.requestLocation()替换为locationManager.startUpdatingLocation()。

   /// 权限public func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {switch status {case .authorizedWhenInUse, .authorizedAlways:// 授权通过,开始更新位置locationManager.startUpdatingLocation()case .denied, .restricted:// 授权失败,提示用户MWToast.showToast("请打开定位服务")MWLogHelper.info("请打开定位服务2",context: "MWLocationHelper")default:break}}

但是需要注意,持续定位不需要时,我们需要手动停止位置更新,调用stopUpdatingLocation()方法:

    public func stopLocation() {locationManager.stopUpdatingLocation()}

逆地理编码

但是要你的应用想获取到位置的详细信息,比如具体的城市,街道等等,我们需要通过经纬度进行逆地理编码,然后将数据回调出去:

    /// 逆地理编码public func reverseGeocodeLocation(location: CLLocation) {let geocoder = CLGeocoder()geocoder.reverseGeocodeLocation(location) { placemarks, error inif let error = error {self.didFailWithError?(error)return}if let placemark = placemarks?.first {let city = placemark.localitylet cityCode = placemark.administrativeArea // 如果你有具体的城市编码需求self.city = cityself.cityCode = Int(cityCode ?? "")DispatchQueue.main.async {self.didUpdateLocation?(self.longitude ?? 0, self.latitude ?? 0)}MWLogHelper.info("逆地里编码 \(city ?? "") \(cityCode ?? "")",context: "MWLocationHelper")}}}

结语

随着iOS对隐私保护和定位权限管理的不断加强,开发者在使用位置服务时需要更加谨慎和细致。选择合适的权限类型,不仅可以保障用户隐私,也能确保应用功能的顺利运行。通过本篇博客,我们深入探讨了如何在iOS中请求和管理定位权限,如何实现单次和持续定位获取,以及如何进行逆地理编码,帮助你在实际开发中应对各种定位需求。

希望这篇文章能够为你的iOS定位开发之路提供有价值的参考。如果你有任何问题或进一步的疑问,欢迎在评论区与我们交流,我们将一起探索更多关于iOS开发的精彩内容。

相关文章:

iOS中的定位实现(逆地理编码)及Info.plist位置权限详解

引言 在现代移动应用开发中,位置服务已经成为不可或缺的一部分。无论是地图导航、社交分享,还是基于位置的个性化推荐,位置数据都为用户提供了更加丰富和智能的体验。然而,随着用户隐私保护的不断加强,iOS对位置权限的…...

【从零开始的LeetCode-算法】3270. 求出数字答案

给你三个 正 整数 num1 &#xff0c;num2 和 num3 。 数字 num1 &#xff0c;num2 和 num3 的数字答案 key 是一个四位数&#xff0c;定义如下&#xff1a; 一开始&#xff0c;如果有数字 少于 四位数&#xff0c;给它补 前导 0 。答案 key 的第 i 个数位&#xff08;1 < …...

Web认证机制 Cookie、Token、Session、JWT、OAuth2 解析

标题 一、Cookie二、Session三、Token四、JWTSSO&#xff08;单点登录&#xff09; 五、OAuth2如何设计权限系统区别总结 Cookie、Token、Session 和 JWT 都是在 Web 开发中常用的身份验证和授权技术&#xff0c;它们各有优缺点&#xff0c;适用于不同的场景。 Cookie 简单易用…...

Docker 基础命令介绍和常见报错解决

介绍一些 docker 可能用到的基础命令&#xff0c;并解决三个常见报错&#xff1a; 权限被拒绝&#xff08;Permission Denied&#xff09;无法连接到 Docker 仓库&#xff08;Timeout Exceeded&#xff09;磁盘空间不足&#xff08;No Space Left on Device&#xff09; 命令以…...

如何轻松导出所有 WordPress URL 为纯文本格式

作为一名多年的 WordPress 使用者&#xff0c;我深知管理一个网站的复杂性。从迁移网站、设置重定向到整理内容结构&#xff0c;每一步都需要精细处理。而拥有所有 URL 的清单&#xff0c;不仅能让这些工作变得更加简单&#xff0c;还能为后续的管理提供极大的便利。其实&#…...

【进程概念精讲】

Susan,在那命运月台前面&#xff0c;再上车&#xff0c;春天开始落叶.................................................................. 文章目录 前言 一、【认识进程】 1、【进程基本概念引入】 2、【进程的描述与组织——进程控制块&#xff08;PCB&#xff09;与进程…...

帽子矩阵--记录

帽子矩阵 H是一个重要的统计工具&#xff0c;用于评估数据点对模型拟合结果的影响。通过计算帽子矩阵的对角线元素&#xff08;杠杆值&#xff09;&#xff0c;我们可以识别出高杠杆点&#xff0c;这些点对模型的影响较大&#xff0c;可能需要特别关注。...

MySQL深入:B+树的演化、索引和索引结构

提示&#xff1a;内容是读《MySQL技术内幕&#xff1a;InnoDB存储引擎》&#xff0c;笔记摘要 文章目录 二叉查找树平衡二叉树(AVL) B树(BTree)B树(BTree)InnoDB B树索引索引结构&#xff08;InnoDB B树&#xff09;B树存放的数据量 二叉查找树 在二叉查找树中&#xff0c;左子…...

axios 实现 无感刷新方案

实现思路 首次登录前端通过接口获取到两个 token&#xff1b;分别是 accessToken、refreshToken; accessToken&#xff1a;正常请求需要传递的 token &#xff1b;refreshToken&#xff1a;当某个请求 401 &#xff0c;就可以通过 refreshToken 获取到新的 accessToken 特殊场…...

Python 三种方式实现自动化任务

在这篇文章中&#xff0c;我们将介绍一些用Python实现机器人过程自动化的包。机器人流程自动化&#xff08;Robotic process automation&#xff0c;简称RPA&#xff09;是指将鼠标点击和键盘按压自动化的过程&#xff0c;即模拟人类用户的操作。RPA用于各种应用程序&#xff0…...

新型创业模式:退休创业。没有工资,不用投资,有时间就干,不强制做,赚钱按贡献分。

这种“退休创业”的创业模式具有独特的吸引力和灵活性&#xff0c;适合那些已退休但希望继续贡献社会价值、赚取额外收入且无需承担太多责任的群体。以下是一个详细的设计思路&#xff1a; 模式概述 目标人群&#xff1a;退休人员&#xff0c;具有一定技能或经验&#xff0c;但…...

Android 项目依赖库无法找到的解决方案

目录 错误信息解析 解决方案 1. 检查依赖版本 2. 检查 Maven 仓库配置 3. 强制刷新 Gradle 缓存 4. 检查网络连接 5. 手动下载依赖 总结 相关推荐 最近&#xff0c;我在编译一个 Android 老项目时遇到了一个问题&#xff0c;错误信息显示无法找到 com.gyf.immersionba…...

在Node.js中如何使用TypeScript

第一步&#xff1a;创建一个Node.js项目的package.json文件 npm init -y第二步&#xff1a;添加TypeScript、添加node.d.ts npm install typescript -D npm install types/node -D第三步&#xff1a;初始化一个tsconfig.json文件 npx tsc --init --rootDir src --outDir lib…...

链表两数加python

一、问题描述 给你两个 非空 的链表&#xff0c;表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的&#xff0c;并且每个节点只能存储 一位 数字。 请你将两个数相加&#xff0c;并以相同形式返回一个表示和的链表。 你可以假设除了数字 0 之外&#xff0c;这两个…...

免费的可以薅羊毛的cloudflare反向代理教程

cloudflare-reverse-proxy 项目代码: https://github.com/EASTCATV/cloudflare-reverse-proxy 本项目是cloudflare反向代理。在cloudflare网站中新建worker&#xff0c;把worker.js文件中的内容复制进去即可使用。 使用方法为在任意url前面加上https://你的域名/proxy/ 即可…...

【每日刷题】Day155

【每日刷题】Day155 &#x1f955;个人主页&#xff1a;开敲&#x1f349; &#x1f525;所属专栏&#xff1a;每日刷题&#x1f34d; &#x1f33c;文章目录&#x1f33c; 1. LCR 108. 单词接龙 - 力扣&#xff08;LeetCode&#xff09; 2. 675. 为高尔夫球比赛砍树 - 力扣(…...

EXCEL延迟退休公式

如图&#xff1a; A B为手工输入 C2EOMONTH(A2,B2*12) D2EOMONTH(C2,IF(C2>DATEVALUE("2025-1-1"),INT((DATEDIF(DATEVALUE("2025-1-1"),C2,"m")4)/4),0)) E2EOMONTH(A2,B2*12IF(EOMONTH(A2,B2*12)>DATEVALUE("2025-1-1"),INT(…...

开源对象存储新选择:在Docker上部署MinIO并实现远程管理

文章目录 前言1. Docker 部署MinIO2. 本地访问MinIO3. Linux安装Cpolar4. 配置MinIO公网地址5. 远程访问MinIO管理界面6. 固定MinIO公网地址 前言 MinIO是一个开源的对象存储服务器&#xff0c;可以在各种环境中运行&#xff0c;例如本地、Docker容器、Kubernetes集群等。它兼…...

Spring Cloud生态圈

目录 Spring Cloud生态圈 核心组件 其他组件 总结 Spring Cloud Alibaba生态圈 核心组件 其他特性 Spring Cloud生态圈 Spring Cloud生态圈是一个为微服务架构提供全方位支持的解决方案集合。它涵盖了多个关键组件和服务&#xff0c;旨在帮助开发者快速构建、部署和管理…...

AI视觉小车基础--4.舵机控制(云台控制)

一、实验准备 控制连接在扩展板上的舵机。如下图所示&#xff0c;按键KEY1为板载元器件&#xff0c;所以不需要外接其他设备。 二、运行代码 # Import the Raspbot library import time from Raspbot_Lib import Raspbot from ipywidgets import interact import ipywidgets a…...

【Rust中的项目管理】

Rust中的项目管理 前言Package&#xff0c;Crate&#xff0c;Module &use &#xff0c;Path通过代码示例解释 Crate&#xff0c;Module &#xff0c;use&#xff0c;Path创建一个package&#xff1a;代码组织化skin.rs 中的代码struct & enum 相对路径和绝对路径引用同…...

【原创】如何备份和还原Ubuntu系统,非常详细!!

前言 我在虚拟机装了一个xfce4的Ubuntu桌面版&#xff0c;外加输入法、IDEA等&#xff0c;我想将这个虚拟机里的系统直接搬到物理机中&#xff0c;那我可以省的再重新装一遍、配置xfce4桌面、修改一堆快捷键还有配置idea了&#xff0c;那直接说干就干。 本教程基于Ubuntu24.0…...

成都栩熙酷网络科技抖音小店是真的

近年来&#xff0c;随着短视频平台的崛起&#xff0c;抖音小店作为一种新兴的购物模式&#xff0c;迅速吸引了大量消费者和商家的关注。在这一潮流中&#xff0c;成都栩熙酷网络科技有限公司&#xff08;以下简称“栩熙酷”&#xff09;凭借其敏锐的市场洞察力和强大的技术实力…...

Python 爬虫数据清洗与存储:基础教程

Python 爬虫数据清洗与存储&#xff1a;基础教程 在爬虫数据获取完成后&#xff0c;数据往往是“原始”的&#xff0c;不适合直接使用。清洗和存储是将爬取到的原始数据转化为有用信息的关键步骤。本文将系统地介绍 Python 中进行数据清洗与存储的基本方法&#xff0c;帮助新手…...

ssm122基于Java的高校教学业绩信息管理系统+jsp(论文+源码)_kaic

毕 业 设 计&#xff08;论 文&#xff09; 题目&#xff1a;高校教学业绩信息管理系统设计与实现 摘 要 现代经济快节奏发展以及不断完善升级的信息化技术&#xff0c;让传统数据信息的管理升级为软件存储&#xff0c;归纳&#xff0c;集中处理数据信息的管理方式。本高校教学…...

Java 基础知识

一.泛型编程 1. 泛型的概念和作用是什么&#xff1f; 概念&#xff1a;泛型&#xff08;Generics&#xff09;是在 JDK 5.0 引入的新特性&#xff0c;允许在定义类、接口和方法时使用类型参数。类型参数在使用时被具体的类型替换。作用&#xff1a; 类型安全性&#xff1a;避…...

深入探索 React Hooks:原理、用法与性能优化全解

一、引言 在现代 React 开发领域,Hooks 已成为不可或缺的一部分,赋予函数组件强大功能,使其能胜任复杂任务。本文将全面剖析 React Hooks,助您深入理解并熟练运用。 二、React Hooks 是什么 (一)Hooks 出现的背景 早期 React 主要依赖类组件,其通过this.state管理状…...

python中父类和子类继承学习

python为啥要使用继承 1. **代码复用**&#xff1a;子类可以继承父类的方法和属性&#xff0c;避免了重复编写相同的代码&#xff0c;提高了代码的复用性。 2. **建立层次结构**&#xff1a;通过继承可以清晰地表示类之间的层次关系&#xff0c;使代码结构更有条理。 3. **扩展…...

Linux——GPIO输入输出裸机实验

学习了正点原子Linux环境下的GPIO的输入输出的裸机实验学习&#xff0c;现在进行一下小结&#xff1a; 启动文件start.S的编写 .global _start .global _bss_start _bss_start:.word __bss_start.global _bss_end _bss_end:.word __bss_end_start:/*设置处理器进入SVC模式*/m…...

华为鸿蒙HarmonyOS NEXT升级HiCar:打造未来出行新体验

随着科技的不断进步&#xff0c;智能出行已成为我们生活中不可或缺的一部分。华为凭借其在智能科技领域的深厚积累&#xff0c;推出了全新的鸿蒙HarmonyOS NEXT系统&#xff0c;旨在为用户打造一个“人车家”的无缝协同出行体验。这一系统的核心亮点之一&#xff0c;就是其内置…...