Core Location 功能详解与应用实践
1. 授权状态处理
根视图控制器可作为位置管理器的代理,实现
locationManager(_:didChangeAuthorizationStatus:)
方法来调用
ManagerHolder
中存储的函数:
func locationManager(_ manager: CLLocationManager,
didChangeAuthorization status: CLAuthorizationStatus) {
switch status {
case .authorizedAlways, .authorizedWhenInUse:
self.managerHolder.doThisWhenAuthorized?()
self.managerHolder.doThisWhenAuthorized = nil
default: break
}
}
在跟踪位置前调用
ManagerHolder
的
checkForLocationAccess
方法,若传入完成函数,若已获授权则立即调用该函数;若状态为
.notDetermined
且弹出授权请求提示框,用户授权后会调用该函数。
2. 位置跟踪
2.1 基本流程
使用位置管理器跟踪用户位置,需确保位置管理器有代理,按需进一步配置,然后调用
startUpdatingLocation
方法。位置管理器会不断调用代理的
locationManager(_:didUpdateLocations:)
方法,直到调用
stopUpdatingLocation
停止跟踪。
graph LR
A[设置代理] --> B[配置位置管理器]
B --> C[调用 startUpdatingLocation]
C --> D[不断调用 didUpdateLocations]
D --> E{是否停止跟踪}
E -- 是 --> F[调用 stopUpdatingLocation]
E -- 否 --> D
2.2 配置属性
| 属性 | 说明 | 可选值 |
|---|---|---|
desiredAccuracy
| 期望的定位精度 |
kCLLocationAccuracyBestForNavigation
、
kCLLocationAccuracyBest
、
kCLLocationAccuracyNearestTenMeters
、
kCLLocationAccuracyHundredMeters
、
kCLLocationAccuracyKilometer
、
kCLLocationAccuracyThreeKilometers
|
distanceFilter
| 距离过滤器,设备移动指定距离才报告位置 |
以米为单位,设置为
kCLDistanceFilterNone
可关闭过滤器
|
pausesLocationUpdatesAutomatically
| 是否自动暂停位置更新 |
Bool
类型,默认
true
,与
activityType
相关
|
2.3 示例代码
self.managerHolder.checkForLocationAccess {
self.locman.desiredAccuracy = kCLLocationAccuracyBest
self.locman.distanceFilter = kCLDistanceFilterNone
self.locman.activityType = .other
self.locman.pausesLocationUpdatesAutomatically = false
self.locman.startUpdatingLocation()
}
在
locationManager(_:didUpdateLocations:)
方法中处理位置更新:
let REQ_ACC : CLLocationAccuracy = 10
func locationManager(_ manager: CLLocationManager,
didUpdateLocations locations: [CLLocation]) {
let loc = locations.last!
let acc = loc.horizontalAccuracy
print(acc)
if acc < 0 || acc > REQ_ACC {
return // wait for the next one
}
let coord = loc.coordinate
print("You are at \(coord.latitude) \(coord.longitude)")
}
3. 获取单次位置
常见错误做法是调用
startUpdatingLocation
后在
locationManager(_:didUpdateLocations:)
中立即停止更新,这可能无法获取准确位置。正确做法是调用
requestLocation
方法:
self.locman.desiredAccuracy = kCLLocationAccuracyBest
self.locman.requestLocation()
在
locationManager(_:didUpdateLocations:)
中处理:
func locationManager(manager: CLLocationManager,
didUpdateLocations locations: [CLLocation]) {
let loc = locations.last!
let coord = loc.coordinate
print("You are at \(coord.latitude) \(coord.longitude)")
}
需注意,调用
requestLocation
不会立即获取准确位置,且若短时间内多次调用可能返回缓存值。
4. 后台位置跟踪
4.1 连续后台位置跟踪
类似于后台播放声音,需在
Info.plist
中设置 “Required background modes” 包含
location
,并将位置管理器的
allowsBackgroundLocationUpdates
设置为
true
。
-
授权类型影响
:
-
When In Use
:设备通过蓝色双倍高度状态栏提醒用户应用在进行后台位置跟踪,用户可点击将应用调至前台。
-
Always
:默认不显示蓝色状态栏,若设置
showsBackgroundLocationIndicator
为
true
则显示。
-
节能建议
:
- 设置较粗的
distanceFilter
值。
- 不要求过高精度。
- 正确设置
activityType
并允许更新暂停。
4.2 位置监控
位置监控由系统代劳,应用无需在后台持续运行,一般需 “Always” 授权。它比全面位置跟踪更节能,依赖基站位置估算设备位置。
-
重要提醒
:务必在不需要时调用
stopMonitoring
方法,否则会持续耗电,用户可能删除应用。
-
应用状态处理
:
-
应用在后台暂停
:唤醒应用接收代理事件。
-
应用未运行
:后台重新启动应用,应用代理会收到
application(_:didFinishLaunchingWithOptions:)
消息。
4.3 位置监控类型
| 监控类型 | 检查方法 | 启动方法 | 代理方法 |
|---|---|---|---|
| 显著位置变化监控 |
significantLocationChangeMonitoringAvailable
|
startMonitoringSignificantLocationChanges
|
locationManager(_:didUpdateLocations:)
|
| 访问监控 |
significantLocationChangeMonitoringAvailable
|
startMonitoringVisits
|
locationManager(_:didVisit:)
|
| 区域监控 |
isMonitoringAvailable(for:CLCircularRegion.self)
|
startMonitoring(for:)
|
locationManager(_:didEnterRegion:)
、
locationManager(_:didExitRegion:)
、
locationManager(_:monitoringDidFailFor:withError:)
|
| 地理围栏本地通知 | 无 |
配置
UNNotificationRequest
并设置
UNLocationNotificationTrigger
| 无 |
5. 设备朝向检测(Heading)
5.1 基本原理与可用性检查
对于配备磁力计的设备,Core Location 支持利用磁力计确定设备的朝向。使用磁力计报告设备相对于磁北的方向时,无需开启定位服务;但要报告真北方向,则需要开启定位服务,因为这依赖于设备的位置。
首先,需要检查所需功能是否可用,即调用
headingAvailable
方法。确认可用后,配置位置管理器并调用
startUpdatingHeading
方法开始更新设备朝向信息。此后,代理会不断收到
locationManager(_:didUpdateHeading:)
方法的调用,直到调用
stopUpdatingHeading
或出现错误调用
locationManager(_:didFailWithError:)
方法。
5.2 朝向对象属性
一个朝向对象是
CLHeading
实例,它有两个重要属性:
-
magneticHeading
:表示相对于磁北的方向,以度为单位(非弧度),顺时针方向。
-
trueHeading
:表示相对于真北的方向,同样以度为单位(非弧度),顺时针方向。若真北方向不可用,该属性值将报告为 -1。要使真北方向可用,需要在设置应用中满足以下两个条件:
- 定位服务已开启(隐私 → 定位服务)。
- 指南针校准已开启(隐私 → 定位服务 → 系统服务)。
5.3 示例代码
以下是一个将设备用作指南针的示例代码:
guard CLLocationManager.headingAvailable() else {return} // no hardware
self.locman.headingFilter = 5
self.locman.headingOrientation = .portrait
self.locman.startUpdatingHeading()
在代理方法中,将设备的朝向以大致的方位方向显示在界面的标签中:
func locationManager(_ manager: CLLocationManager,
didUpdateHeading newHeading: CLHeading) {
var h = newHeading.magneticHeading
let h2 = newHeading.trueHeading // -1 if no location info
if h2 >= 0 {
h = h2
}
let cards = ["N", "NE", "E", "SE", "S", "SW", "W", "NW"]
var dir = "N"
for (ix, card) in cards.enumerated() {
if h >= Double(ix * 45) && h < Double((ix + 1) * 45) {
dir = card
break
}
}
self.lab.text = dir
}
5.4 校准对话框处理
如果希望在需要时允许系统的指南针校准对话框出现,需要实现以下代理方法并返回
true
:
func locationManagerShouldDisplayHeadingCalibration(_ manager: CLLocationManager) -> Bool {
return true
}
6. 总结
Core Location 框架为开发者提供了强大而灵活的位置和朝向检测功能。通过合理使用授权状态处理、位置跟踪、单次位置获取、后台位置跟踪以及设备朝向检测等功能,可以开发出各种与位置相关的应用。
在使用这些功能时,需要注意以下几点:
- 授权处理:确保正确处理用户的授权状态,避免因授权问题导致功能无法正常使用。
- 节能优化:在满足应用需求的前提下,尽量优化定位精度、距离过滤器和自动暂停更新等设置,以节省设备电量。
- 资源管理:及时停止不必要的位置跟踪和监控,避免浪费系统资源和消耗过多电量,影响用户体验。
通过遵循这些原则,开发者可以充分利用 Core Location 框架的优势,为用户提供优质的位置相关服务。
以下是一个简单的流程图,展示了使用 Core Location 进行位置跟踪的基本流程:
graph LR
A[检查授权状态] --> B{是否授权}
B -- 是 --> C[配置位置管理器]
B -- 否 --> D[请求授权]
D --> A
C --> E[开始位置跟踪]
E --> F{是否需要停止跟踪}
F -- 是 --> G[停止位置跟踪]
F -- 否 --> E
同时,为了更清晰地对比不同的位置监控类型,这里再次给出一个表格:
| 监控类型 | 检查方法 | 启动方法 | 代理方法 |
| ---- | ---- | ---- | ---- |
| 显著位置变化监控 |
significantLocationChangeMonitoringAvailable
|
startMonitoringSignificantLocationChanges
|
locationManager(_:didUpdateLocations:)
|
| 访问监控 |
significantLocationChangeMonitoringAvailable
|
startMonitoringVisits
|
locationManager(_:didVisit:)
|
| 区域监控 |
isMonitoringAvailable(for:CLCircularRegion.self)
|
startMonitoring(for:)
|
locationManager(_:didEnterRegion:)
、
locationManager(_:didExitRegion:)
、
locationManager(_:monitoringDidFailFor:withError:)
|
| 地理围栏本地通知 | 无 | 配置
UNNotificationRequest
并设置
UNLocationNotificationTrigger
| 无 |
通过以上的介绍和示例,相信开发者可以更好地理解和应用 Core Location 框架,开发出更加优秀的位置相关应用。
超级会员免费看
2435

被折叠的 条评论
为什么被折叠?



