SwiftUI获取用户的位置信息(CLLocationManager,CLLocationManagerDelegate)

本篇文章将会介绍一下在SwiftUI中如何通过CorLocation框架获取用户的位置信息,因为获取位置信息属于用户的隐私信息,所以需要在Info.plist文件里面加上访问位置权限的说明。
在这里插入图片描述
关于位置信息,可以请求两种级别的许可:alwayswhen in use。根据我们应用需求进行选择。我们需要在Info.plist文件上上添加这个条目,同时必须提供一个描述,向用户解释为什么你的应用程序需要位置信息(该文本将出现在询问用户权限的对话框中),比如说:“XXX App需要访问您的位置以提供基于位置的服务。”

本文采用when in use这种方式:
![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/bb719f87fd4e48dd9f578e6e7abdee60.png = 600x)

下面创建一个处理位置信息的类LocationManager

import Foundation
import CoreLocation

final class LocationManager: NSObject, CLLocationManagerDelegate, ObservableObject {

  // 记录位置信息
  @Published var currentLocation: CLLocationCoordinate2D?

  // 初始化CLLocationManager实例
  private var locManager = CLLocationManager()

  func checkLocationAuthorization() {
    // 设置代理
    locManager.delegate = self

    // 获取用户授权状态
    let authorizationStatus = locManager.authorizationStatus


    DispatchQueue.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 = nil
    locManager.delegate = nil
    locManager.stopUpdatingLocation()
  }

  // 当用户的位置权限状态发生变化时调用,例如用户从拒绝状态改为允许状态。用于根据当前的授权状态调整应用的行为,如在用户授权后开始位置更新。
  func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) {
    if manager.authorizationStatus == .denied {
      locManager.stopUpdatingLocation()
    } else if manager.authorizationStatus == .authorizedAlways || manager.authorizationStatus == .authorizedWhenInUse {
      locManager.startUpdatingLocation()
    }
  }
}

完整代码如上,下面逐步看一下:

首先LocationManager类继承了NSObject类,并实现了CLLocationManagerDelegateObservableObject协议。
实现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)

最后,希望能够帮助到有需要的朋友,如果觉得有帮助,还望点个赞,添加个关注,笔者也会不断地努力,写出更多更好用的文章。

  • 10
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值