本篇文章将会介绍一下在SwiftUI
中如何通过CorLocation
框架获取用户的位置信息,因为获取位置信息属于用户的隐私信息,所以需要在Info.plist
文件里面加上访问位置权限的说明。
关于位置信息,可以请求两种级别的许可:always
和when in use
。根据我们应用需求进行选择。我们需要在Info.plist
文件上上添加这个条目,同时必须提供一个描述,向用户解释为什么你的应用程序需要位置信息(该文本将出现在询问用户权限的对话框中),比如说:“XXX App需要访问您的位置以提供基于位置的服务。”
本文采用when in use
这种方式:
![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/bb719f87fd4e48dd9f578e6e7abdee60.png = 600x)
下面创建一个处理位置信息的类LocationManager
。
import Foundation
import CoreLocationfinal class LocationManager: NSObject, CLLocationManagerDelegate, ObservableObject {// 记录位置信息@Published var currentLocation: CLLocationCoordinate2D?// 初始化CLLocationManager实例private var locManager = CLLocationManager()func checkLocationAuthorization() {// 设置代理locManager.delegate = self// 获取用户授权状态let authorizationStatus = locManager.authorizationStatusDispatchQueue.global().async { [weak self] in// 判断用户设备的系统位置权限是否开启,而非App的。该判断需要异步进行,否则会卡主线程。if CLLocationManager.locationServicesEnabled() {// 如果设备系统位置权限开启了,回主线程继续操作DispatchQueue.main.async {if authorizationStatus == .authorizedAlways || authorizationStatus == .authorizedWhenInUse {// 如果用户授权了,开启位置更新。self?.locManager.startUpdatingLocation()} else if authorizationStatus == .notDetermined {// 如果用户未曾选择过,那么弹出授权框。self?.locManager.requestWhenInUseAuthorization()} else {// 用户拒绝了,停止位置更新。self?.locManager.stopUpdatingLocation()}}} else {// 如果设备系统位置权限未开启,回主线程继续操作DispatchQueue.main.async {if authorizationStatus == .notDetermined {// 如果用户未曾选择过,那么弹出授权框。self?.locManager.requestWhenInUseAuthorization()} else {// 因系统位置权限未开启,停止位置更新。self?.locManager.stopUpdatingLocation()}}}}}// MARK: - CLLocationManagerDelegate// 每当位置更新时都会被调用,这里更新currentLocation变量。func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {if let newLocation = manager.location, !(newLocation.coordinate.longitude == 0.0 && newLocation.coordinate.latitude == 0.0) {currentLocation = newLocation.coordinate}}// 当位置管理器无法获取位置或发生错误时调用。func locationManager(_ manager: CLLocationManager, didFailWithError error: any Error) {currentLocation = nillocManager.delegate = nillocManager.stopUpdatingLocation()}// 当用户的位置权限状态发生变化时调用,例如用户从拒绝状态改为允许状态。用于根据当前的授权状态调整应用的行为,如在用户授权后开始位置更新。func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) {if manager.authorizationStatus == .denied {locManager.stopUpdatingLocation()} else if manager.authorizationStatus == .authorizedAlways || manager.authorizationStatus == .authorizedWhenInUse {locManager.startUpdatingLocation()}}
}
完整代码如上,下面逐步看一下:
首先LocationManager
类继承了NSObject
类,并实现了CLLocationManagerDelegate
和ObservableObject
协议。
实现CLLocationManagerDelegate
协议是为了处理位置信息以及授权等变更的情况;
实现ObservableObject
协议,并定义了一个@Published
变量,供UI显示位置信息使用。
在该类中定义两个属性,说明见注释。
// 记录位置信息,变化时通知用到该变量的UI进行刷新。@Published var currentLocation: CLLocationCoordinate2D?// 初始化CLLocationManager实例private var locManager = CLLocationManager()
目前该类还提供了一个对外的方法checkLocationAuthorization
(),该方法内设置了delegate
,判断系统位置权限情况以及用户针对App的授权情况,根据不同的情况采取对应的处理方式,具体见注释。
特别说明一下CLLocationManager.locationServicesEnabled()
方法获取系统位置授权情况,需要在异步进行,否则卡UI。
在CLLocationManagerDelegate
中,我们实现了三个基本的方法,分别处理位置信息变更,位置信息获取失败,以及用户授权状态的改变。
上面都搞定后,弄个界面显示一下位置信息:
struct LocationViewDemo: View {@StateObject private var locationManager = LocationManager()var body: some View {VStack(spacing: 30) {if let currentLocation = locationManager.currentLocation {VStack(spacing: 20) {Text("Latitude: \(currentLocation.latitude)")Text("Longitude: \(currentLocation.longitude)")}}Button("Get location") {locationManager.checkLocationAuthorization()}.buttonStyle(.borderedProminent)}.padding()}
}
App首次运行起来后:
点击后:
授权后,位置信息就显示出来了。
弹出授权框,我们可以调用下面两个方法,不同的方法对应Info.plist
文件中不同配置,匹配不上就无法弹框了。
requestAlwaysAuthorization()
requestWhenInUseAuthorization()
关于manager,还有一个请求一次位置信息的方法:
locManager.requestLocation()
CLLocationManagerDelegate
代码方法的说明:
// 每当位置更新时都会被调用,这里更新currentLocation变量。
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation])
// 当位置管理器无法获取位置或发生错误时调用。
func locationManager(_ manager: CLLocationManager, didFailWithError error: any Error)
/// 当用户的位置权限状态发生变化时调用,例如用户从拒绝状态改为允许状态。
/// 用于根据当前的授权状态调整应用的行为,如在用户授权后开始位置更新。
func locationManagerDidChangeAuthorization(_ manager: CLLocationManager)
/// 位置更新暂停时被调用
func locationManagerDidPauseLocationUpdates(_ manager: CLLocationManager)
/// 位置更新恢复时被调用
func locationManagerDidResumeLocationUpdates(_ manager: CLLocationManager)
/// 用户进入一个地理区域时被调用
func locationManager(_ manager: CLLocationManager, didEnterRegion region: CLRegion)
/// 用户离开一个地理区域时被调用
func locationManager(_ manager: CLLocationManager, didExitRegion region: CLRegion)
最后,希望能够帮助到有需要的朋友,如果觉得有帮助,还望点个赞,添加个关注,笔者也会不断地努力,写出更多更好用的文章。