axiom-core-location-ref
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseCore Location Reference
Core Location 参考文档
Comprehensive API reference for modern Core Location (iOS 17+).
适用于iOS 17及以上版本的现代Core Location完整API参考文档。
When to Use
适用场景
- Need API signatures for CLLocationUpdate, CLMonitor, CLServiceSession
- Implementing geofencing or region monitoring
- Configuring background location updates
- Understanding authorization patterns
- Debugging location service issues
- 需要CLLocationUpdate、CLMonitor、CLServiceSession的API签名
- 实现地理围栏或区域监控功能
- 配置后台定位更新
- 理解授权模式
- 调试定位服务相关问题
Related Skills
相关技能
- — Anti-patterns, decision trees, pressure scenarios
axiom-core-location - — Symptom-based troubleshooting
axiom-core-location-diag - — Location as battery subsystem (accuracy vs power)
axiom-energy-ref
- — 反模式、决策树、压力场景
axiom-core-location - — 基于症状的故障排除
axiom-core-location-diag - — 定位作为电池子系统(精度与功耗的平衡)
axiom-energy-ref
Part 1: Modern API Overview (iOS 17+)
第一部分:现代API概述(iOS 17+)
Four key classes replace legacy CLLocationManager patterns:
| Class | Purpose | iOS |
|---|---|---|
| AsyncSequence for location updates | 17+ |
| Condition-based geofencing/beacons | 17+ |
| Declarative authorization goals | 18+ |
| Background location support | 17+ |
Migration path: Legacy CLLocationManager still works, but new APIs provide:
- Swift concurrency (async/await)
- Automatic pause/resume
- Simplified authorization
- Better battery efficiency
四个核心类替代了传统的CLLocationManager模式:
| 类 | 用途 | iOS版本 |
|---|---|---|
| 用于定位更新的AsyncSequence | 17+ |
| 基于条件的地理围栏/信标监控 | 17+ |
| 声明式授权目标 | 18+ |
| 后台定位支持 | 17+ |
迁移路径:传统的CLLocationManager仍可使用,但新API具备以下优势:
- Swift并发(async/await)
- 自动暂停/恢复
- 简化的授权流程
- 更优的电池效率
Part 2: CLLocationUpdate API
第二部分:CLLocationUpdate API
Basic Usage
基础用法
swift
import CoreLocation
Task {
do {
for try await update in CLLocationUpdate.liveUpdates() {
if let location = update.location {
// Process location
}
if update.isStationary {
break // Stop when user stops moving
}
}
} catch {
// Handle location errors
}
}swift
import CoreLocation
Task {
do {
for try await update in CLLocationUpdate.liveUpdates() {
if let location = update.location {
// 处理定位信息
}
if update.isStationary {
break // 当用户停止移动时停止更新
}
}
} catch {
// 处理定位错误
}
}LiveConfiguration Options
LiveConfiguration 选项
swift
CLLocationUpdate.liveUpdates(.default)
CLLocationUpdate.liveUpdates(.automotiveNavigation)
CLLocationUpdate.liveUpdates(.otherNavigation)
CLLocationUpdate.liveUpdates(.fitness)
CLLocationUpdate.liveUpdates(.airborne)Choose based on use case. If unsure, use or omit parameter.
.defaultswift
CLLocationUpdate.liveUpdates(.default)
CLLocationUpdate.liveUpdates(.automotiveNavigation)
CLLocationUpdate.liveUpdates(.otherNavigation)
CLLocationUpdate.liveUpdates(.fitness)
CLLocationUpdate.liveUpdates(.airborne)根据使用场景选择对应的选项。若不确定,使用或省略参数。
.defaultKey Properties
核心属性
| Property | Type | Description |
|---|---|---|
| | Current location (nil if unavailable) |
| | True when device stopped moving |
| | User denied location access |
| | Location services disabled system-wide |
| | Awaiting user authorization decision |
| | Reduced accuracy (updates every 15-20 min) |
| | Cannot determine location |
| | Can't request auth (not in foreground) |
| 属性 | 类型 | 描述 |
|---|---|---|
| | 当前定位信息(不可用时为nil) |
| | 设备是否处于静止状态 |
| | 用户是否拒绝了定位权限 |
| | 系统级定位服务是否已禁用 |
| | 是否正在等待用户的授权决策 |
| | 是否启用了降低精度模式(每15-20分钟更新一次) |
| | 无法获取定位信息 |
| | 无法请求权限(应用未处于前台) |
Automatic Pause/Resume
自动暂停/恢复
When device becomes stationary:
- Final update delivered with and valid
isStationary = truelocation - Updates pause (saves battery)
- When device moves, updates resume with
isStationary = false
No action required—happens automatically.
当设备处于静止状态时:
- 会发送最后一次更新,其中且
isStationary = true有效location - 更新自动暂停(节省电量)
- 当设备开始移动时,更新恢复,
isStationary = false
无需额外操作——该过程自动完成。
AsyncSequence Operations
AsyncSequence 操作
swift
// Get first location with speed > 10 m/s
let fastUpdate = try await CLLocationUpdate.liveUpdates()
.first { $0.location?.speed ?? 0 > 10 }
// WARNING: Avoid filters that may never match (e.g., horizontalAccuracy < 1)swift
// 获取第一个速度超过10m/s的定位信息
let fastUpdate = try await CLLocationUpdate.liveUpdates()
.first { $0.location?.speed ?? 0 > 10 }
// 警告:避免使用可能永远无法匹配的过滤器(例如horizontalAccuracy < 1)Part 3: CLMonitor API
第三部分:CLMonitor API
Swift actor for monitoring geographic conditions and beacons.
用于监控地理条件和信标的Swift actor。
Basic Geofencing
基础地理围栏
swift
let monitor = await CLMonitor("MyMonitor")
// Add circular region
let condition = CLMonitor.CircularGeographicCondition(
center: CLLocationCoordinate2D(latitude: 37.33, longitude: -122.01),
radius: 100
)
await monitor.add(condition, identifier: "ApplePark")
// Await events
for try await event in monitor.events {
switch event.state {
case .satisfied: // User entered region
handleEntry(event.identifier)
case .unsatisfied: // User exited region
handleExit(event.identifier)
case .unknown:
break
@unknown default:
break
}
}swift
let monitor = await CLMonitor("MyMonitor")
// 添加圆形区域
let condition = CLMonitor.CircularGeographicCondition(
center: CLLocationCoordinate2D(latitude: 37.33, longitude: -122.01),
radius: 100
)
await monitor.add(condition, identifier: "ApplePark")
// 监听事件
for try await event in monitor.events {
switch event.state {
case .satisfied: // 用户进入区域
handleEntry(event.identifier)
case .unsatisfied: // 用户离开区域
handleExit(event.identifier)
case .unknown:
break
@unknown default:
break
}
}CircularGeographicCondition
CircularGeographicCondition
swift
CLMonitor.CircularGeographicCondition(
center: CLLocationCoordinate2D,
radius: CLLocationDistance // meters, minimum ~100m effective
)swift
CLMonitor.CircularGeographicCondition(
center: CLLocationCoordinate2D,
radius: CLLocationDistance // 单位:米,有效最小半径约100米
)BeaconIdentityCondition
BeaconIdentityCondition
Three granularity levels:
swift
// All beacons with UUID (any site)
CLMonitor.BeaconIdentityCondition(uuid: myUUID)
// Specific site (UUID + major)
CLMonitor.BeaconIdentityCondition(uuid: myUUID, major: 100)
// Specific beacon (UUID + major + minor)
CLMonitor.BeaconIdentityCondition(uuid: myUUID, major: 100, minor: 5)三种粒度级别:
swift
// 监控所有具有该UUID的信标(任意站点)
CLMonitor.BeaconIdentityCondition(uuid: myUUID)
// 监控特定站点(UUID + major)
CLMonitor.BeaconIdentityCondition(uuid: myUUID, major: 100)
// 监控特定信标(UUID + major + minor)
CLMonitor.BeaconIdentityCondition(uuid: myUUID, major: 100, minor: 5)Condition Limit
条件数量限制
Maximum 20 conditions per app. Prioritize what to monitor. Swap regions dynamically based on user location if needed.
每个应用最多支持20个条件。优先监控关键区域,必要时可根据用户位置动态替换区域。
Adding with Assumed State
假设初始状态添加条件
swift
// If you know initial state
await monitor.add(condition, identifier: "Work", assuming: .unsatisfied)Core Location will correct if assumption wrong.
swift
// 若已知初始状态
await monitor.add(condition, identifier: "Work", assuming: .unsatisfied)Core Location会在假设错误时自动修正状态。
Accessing Records
访问记录
swift
// Get single record
if let record = await monitor.record(for: "ApplePark") {
let condition = record.condition
let lastEvent = record.lastEvent
let state = lastEvent.state
let date = lastEvent.date
}
// Get all identifiers
let allIds = await monitor.identifiersswift
// 获取单个记录
if let record = await monitor.record(for: "ApplePark") {
let condition = record.condition
let lastEvent = record.lastEvent
let state = lastEvent.state
let date = lastEvent.date
}
// 获取所有标识符
let allIds = await monitor.identifiersEvent Properties
事件属性
| Property | Description |
|---|---|
| String identifier of condition |
| |
| When state changed |
| For wildcard beacons, actual UUID/major/minor detected |
| Too many conditions (max 20) |
| Condition type not available |
| Reduced accuracy prevents monitoring |
| 属性 | 描述 |
|---|---|
| 条件的字符串标识符 |
| |
| 状态变更的时间 |
| 对于通配符信标,显示检测到的实际UUID/major/minor |
| 是否超出条件数量上限(最多20个) |
| 条件类型是否不被支持 |
| 降低精度模式是否影响监控 |
Critical Requirements
关键要求
- One monitor per name — Only one instance with given name at a time
- Always await events — Events only become after handling
lastEvent - Reinitialize on launch — Recreate monitor in
didFinishLaunchingWithOptions
- 每个名称对应一个监控实例——同一时间只能存在一个指定名称的CLMonitor实例
- 始终监听事件——事件只有在被处理后才会成为
lastEvent - 启动时重新初始化——在中重新创建监控实例
didFinishLaunchingWithOptions
Part 4: CLServiceSession API (iOS 18+)
第四部分:CLServiceSession API(iOS 18+)
Declarative authorization—tell Core Location what you need, not what to do.
声明式授权——告知Core Location你的需求,而非具体操作。
Basic Usage
基础用法
swift
// Hold session for duration of feature
let session = CLServiceSession(authorization: .whenInUse)
for try await update in CLLocationUpdate.liveUpdates() {
// Process updates
}swift
// 在功能存续期间持有会话
let session = CLServiceSession(authorization: .whenInUse)
for try await update in CLLocationUpdate.liveUpdates() {
// 处理定位更新
}Authorization Requirements
授权要求
swift
CLServiceSession(authorization: .none) // No auth request
CLServiceSession(authorization: .whenInUse) // Request When In Use
CLServiceSession(authorization: .always) // Request Always (must start in foreground)swift
CLServiceSession(authorization: .none) // 不请求权限
CLServiceSession(authorization: .whenInUse) // 请求使用期间权限
CLServiceSession(authorization: .always) // 请求始终允许权限(必须在前台启动)Full Accuracy Request
全精度请求
swift
// For features requiring precise location (e.g., navigation)
CLServiceSession(
authorization: .whenInUse,
fullAccuracyPurposeKey: "NavigationPurpose" // Key in Info.plist
)Requires in Info.plist.
NSLocationTemporaryUsageDescriptionDictionaryswift
// 对于需要精确定位的功能(例如导航)
CLServiceSession(
authorization: .whenInUse,
fullAccuracyPurposeKey: "NavigationPurpose" // Info.plist中的键
)需要在Info.plist中配置。
NSLocationTemporaryUsageDescriptionDictionaryImplicit Sessions
隐式会话
Iterating or creates implicit session with goal.
CLLocationUpdate.liveUpdates()CLMonitor.events.whenInUseTo disable implicit sessions:
xml
<!-- Info.plist -->
<key>NSLocationRequireExplicitServiceSession</key>
<true/>遍历或时,会自动创建一个授权目标为的隐式会话。
CLLocationUpdate.liveUpdates()CLMonitor.events.whenInUse如需禁用隐式会话:
xml
<!-- Info.plist -->
<key>NSLocationRequireExplicitServiceSession</key>
<true/>Session Layering
会话分层
Don't replace sessions—layer them:
swift
// Base session for app
let baseSession = CLServiceSession(authorization: .whenInUse)
// Additional session when navigation feature active
let navSession = CLServiceSession(
authorization: .whenInUse,
fullAccuracyPurposeKey: "Nav"
)
// Both sessions active simultaneously不要替换会话——而是分层使用:
swift
// 应用的基础会话
let baseSession = CLServiceSession(authorization: .whenInUse)
// 导航功能激活时的附加会话
let navSession = CLServiceSession(
authorization: .whenInUse,
fullAccuracyPurposeKey: "Nav"
)
// 两个会话同时处于活跃状态Diagnostic Properties
诊断属性
swift
for try await diagnostic in session.diagnostics {
if diagnostic.authorizationDenied {
// User denied—offer alternative
}
if diagnostic.authorizationDeniedGlobally {
// Location services off system-wide
}
if diagnostic.insufficientlyInUse {
// Can't request auth (not foreground)
}
if diagnostic.alwaysAuthorizationDenied {
// Always auth specifically denied
}
if !diagnostic.authorizationRequestInProgress {
// Decision made (granted or denied)
break
}
}swift
for try await diagnostic in session.diagnostics {
if diagnostic.authorizationDenied {
// 用户拒绝了权限——提供替代方案
}
if diagnostic.authorizationDeniedGlobally {
// 系统级定位服务已关闭
}
if diagnostic.insufficientlyInUse {
// 无法请求权限(应用未处于前台)
}
if diagnostic.alwaysAuthorizationDenied {
// 始终允许权限被明确拒绝
}
if !diagnostic.authorizationRequestInProgress {
// 授权决策已完成(允许或拒绝)
break
}
}Session Lifecycle
会话生命周期
Sessions persist through:
- App backgrounding
- App suspension
- App termination (Core Location tracks)
On relaunch, recreate sessions immediately in .
didFinishLaunchingWithOptions会话会在以下场景中持续存在:
- 应用进入后台
- 应用被挂起
- 应用终止(Core Location会跟踪会话)
应用重启时,需立即在中重新创建会话。
didFinishLaunchingWithOptionsPart 5: Authorization State Machine
第五部分:授权状态机
Authorization Levels
授权级别
| Status | Description |
|---|---|
| User hasn't decided |
| Parental controls prevent access |
| User explicitly refused |
| Access while app active |
| Background access |
| 状态 | 描述 |
|---|---|
| 用户尚未做出决策 |
| 家长控制限制了定位访问 |
| 用户明确拒绝了权限 |
| 应用活跃时可访问定位 |
| 后台也可访问定位 |
Accuracy Authorization
精度授权
| Value | Description |
|---|---|
| Precise location |
| Approximate (~5km), updates every 15-20 min |
| 值 | 描述 |
|---|---|
| 精确定位 |
| 近似定位(约5公里),每15-20分钟更新一次 |
Required Info.plist Keys
必需的Info.plist键
xml
<!-- Required for When In Use -->
<key>NSLocationWhenInUseUsageDescription</key>
<string>We need your location to show nearby places</string>
<!-- Required for Always -->
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>We track your location to send arrival reminders</string>
<!-- Optional: default to reduced accuracy -->
<key>NSLocationDefaultAccuracyReduced</key>
<true/>xml
<!-- 使用期间权限必需 -->
<key>NSLocationWhenInUseUsageDescription</key>
<string>我们需要获取你的位置以显示附近地点</string>
<!-- 始终允许权限必需 -->
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>我们会跟踪你的位置以发送到达提醒</string>
<!-- 可选:默认使用降低精度模式 -->
<key>NSLocationDefaultAccuracyReduced</key>
<true/>Legacy Authorization Pattern
传统授权模式
swift
@MainActor
class LocationManager: NSObject, CLLocationManagerDelegate {
private let manager = CLLocationManager()
func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) {
switch manager.authorizationStatus {
case .notDetermined:
manager.requestWhenInUseAuthorization()
case .authorizedWhenInUse, .authorizedAlways:
enableLocationFeatures()
case .denied, .restricted:
disableLocationFeatures()
@unknown default:
break
}
}
}swift
@MainActor
class LocationManager: NSObject, CLLocationManagerDelegate {
private let manager = CLLocationManager()
func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) {
switch manager.authorizationStatus {
case .notDetermined:
manager.requestWhenInUseAuthorization()
case .authorizedWhenInUse, .authorizedAlways:
enableLocationFeatures()
case .denied, .restricted:
disableLocationFeatures()
@unknown default:
break
}
}
}Part 6: Background Location
第六部分:后台定位
Requirements
要求
- Background mode capability: Signing & Capabilities → Background Modes → Location updates
- Info.plist: Adds with
UIBackgroundModesvaluelocation - CLBackgroundActivitySession or LiveActivity
- 后台模式权限:在Signing & Capabilities中开启Background Modes → Location updates
- Info.plist:添加键,值包含
UIBackgroundModeslocation - CLBackgroundActivitySession 或 LiveActivity
CLBackgroundActivitySession
CLBackgroundActivitySession
swift
// Create and HOLD reference (deallocation invalidates session)
var backgroundSession: CLBackgroundActivitySession?
func startBackgroundTracking() {
// Must start from foreground
backgroundSession = CLBackgroundActivitySession()
Task {
for try await update in CLLocationUpdate.liveUpdates() {
processUpdate(update)
}
}
}
func stopBackgroundTracking() {
backgroundSession?.invalidate()
backgroundSession = nil
}swift
// 创建并持有引用(释放会使会话失效)
var backgroundSession: CLBackgroundActivitySession?
func startBackgroundTracking() {
// 必须从前台启动
backgroundSession = CLBackgroundActivitySession()
Task {
for try await update in CLLocationUpdate.liveUpdates() {
processUpdate(update)
}
}
}
func stopBackgroundTracking() {
backgroundSession?.invalidate()
backgroundSession = nil
}Background Indicator
后台指示器
Blue status bar/pill appears when:
- App authorized as "When In Use"
- App receiving location in background
- CLBackgroundActivitySession active
当以下条件满足时,会显示蓝色状态栏/标记:
- 应用被授权为"使用期间允许"
- 应用在后台接收定位更新
- CLBackgroundActivitySession处于活跃状态
App Lifecycle
应用生命周期
- Foreground → Background: Session continues
- Background → Suspended: Session preserved, updates pause
- Suspended → Terminated: Core Location tracks session
- Terminated → Background launch: Recreate session immediately
swift
func application(_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Recreate background session if was tracking
if wasTrackingLocation {
backgroundSession = CLBackgroundActivitySession()
startLocationUpdates()
}
return true
}- 前台→后台:会话继续运行
- 后台→挂起:会话保留,更新暂停
- 挂起→终止:Core Location会跟踪会话
- 终止→后台启动:立即重新创建会话
swift
func application(_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// 若之前在跟踪定位,重新创建后台会话
if wasTrackingLocation {
backgroundSession = CLBackgroundActivitySession()
startLocationUpdates()
}
return true
}Part 7: Legacy APIs (iOS 12-16)
第七部分:传统API(iOS 12-16)
CLLocationManager Delegate Pattern
CLLocationManager 代理模式
swift
class LocationManager: NSObject, CLLocationManagerDelegate {
private let manager = CLLocationManager()
override init() {
super.init()
manager.delegate = self
manager.desiredAccuracy = kCLLocationAccuracyBest
manager.distanceFilter = 10 // meters
}
func startUpdates() {
manager.startUpdatingLocation()
}
func stopUpdates() {
manager.stopUpdatingLocation()
}
func locationManager(_ manager: CLLocationManager,
didUpdateLocations locations: [CLLocation]) {
guard let location = locations.last else { return }
// Process location
}
}swift
class LocationManager: NSObject, CLLocationManagerDelegate {
private let manager = CLLocationManager()
override init() {
super.init()
manager.delegate = self
manager.desiredAccuracy = kCLLocationAccuracyBest
manager.distanceFilter = 10 // 米
}
func startUpdates() {
manager.startUpdatingLocation()
}
func stopUpdates() {
manager.stopUpdatingLocation()
}
func locationManager(_ manager: CLLocationManager,
didUpdateLocations locations: [CLLocation]) {
guard let location = locations.last else { return }
// 处理定位信息
}
}Accuracy Constants
精度常量
| Constant | Accuracy | Battery Impact |
|---|---|---|
| ~5m | Highest |
| ~10m | Very High |
| ~10m | High |
| ~100m | Medium |
| ~1km | Low |
| ~3km | Very Low |
| ~5km | Lowest |
| 常量 | 精度 | 电池影响 |
|---|---|---|
| ~5米 | 最高 |
| ~10米 | 极高 |
| ~10米 | 高 |
| ~100米 | 中等 |
| ~1公里 | 低 |
| ~3公里 | 极低 |
| ~5公里 | 最低 |
Legacy Region Monitoring
传统区域监控
swift
// Deprecated in iOS 17, use CLMonitor instead
let region = CLCircularRegion(
center: coordinate,
radius: 100,
identifier: "MyRegion"
)
region.notifyOnEntry = true
region.notifyOnExit = true
manager.startMonitoring(for: region)swift
// iOS 17中已废弃,建议使用CLMonitor
let region = CLCircularRegion(
center: coordinate,
radius: 100,
identifier: "MyRegion"
)
region.notifyOnEntry = true
region.notifyOnExit = true
manager.startMonitoring(for: region)Significant Location Changes
显著位置变化监控
Low-power alternative for coarse tracking:
swift
manager.startMonitoringSignificantLocationChanges()
// Updates ~500m movements, works in background低功耗的粗略定位替代方案:
swift
manager.startMonitoringSignificantLocationChanges()
// 当位置变化约500米时更新,支持后台运行Visit Monitoring
到访监控
Detect arrivals/departures:
swift
manager.startMonitoringVisits()
func locationManager(_ manager: CLLocationManager, didVisit visit: CLVisit) {
let arrival = visit.arrivalDate
let departure = visit.departureDate
let coordinate = visit.coordinate
}检测到达/离开事件:
swift
manager.startMonitoringVisits()
func locationManager(_ manager: CLLocationManager, didVisit visit: CLVisit) {
let arrival = visit.arrivalDate
let departure = visit.departureDate
let coordinate = visit.coordinate
}Part 8: Geofencing Best Practices
第八部分:地理围栏最佳实践
Region Size
区域大小
- Minimum effective radius: ~100 meters
- Smaller regions: May not trigger reliably
- Larger regions: More reliable but less precise
- 有效最小半径:约100米
- 更小的区域:可能无法可靠触发
- 更大的区域:更可靠但精度较低
20-Region Limit Strategy
20个区域上限的应对策略
swift
// Dynamic region management
func updateMonitoredRegions(userLocation: CLLocation) async {
let nearbyPOIs = fetchNearbyPOIs(around: userLocation, limit: 20)
// Remove old regions
for id in await monitor.identifiers {
if !nearbyPOIs.contains(where: { $0.id == id }) {
await monitor.remove(id)
}
}
// Add new regions
for poi in nearbyPOIs {
let condition = CLMonitor.CircularGeographicCondition(
center: poi.coordinate,
radius: 100
)
await monitor.add(condition, identifier: poi.id)
}
}swift
// 动态区域管理
func updateMonitoredRegions(userLocation: CLLocation) async {
let nearbyPOIs = fetchNearbyPOIs(around: userLocation, limit: 20)
// 移除旧区域
for id in await monitor.identifiers {
if !nearbyPOIs.contains(where: { $0.id == id }) {
await monitor.remove(id)
}
}
// 添加新区域
for poi in nearbyPOIs {
let condition = CLMonitor.CircularGeographicCondition(
center: poi.coordinate,
radius: 100
)
await monitor.add(condition, identifier: poi.id)
}
}Entry/Exit Timing
进入/离开触发时机
- Entry: Usually within seconds to minutes
- Exit: May take 3-5 minutes after leaving
- Accuracy depends on: Cell towers, WiFi, GPS availability
- 进入:通常在几秒到几分钟内触发
- 离开:离开后可能需要3-5分钟才会触发
- 精度取决于:基站、WiFi、GPS的可用性
Persistence
持久性
- Conditions persist across app launches
- Must reinitialize monitor with same name on launch
- Core Location wakes app for events
- 条件会在应用重启后保留
- 启动时必须使用相同名称重新初始化监控实例
- Core Location会在事件触发时唤醒应用
Part 9: Testing and Simulation
第九部分:测试与模拟
Xcode Location Simulation
Xcode定位模拟
- Run on simulator
- Debug → Simulate Location → Choose location
- Or use custom GPX file
- 在模拟器上运行应用
- 点击Debug → Simulate Location → 选择位置
- 或使用自定义GPX文件
Custom GPX Route
自定义GPX路线
xml
<?xml version="1.0"?>
<gpx version="1.1">
<wpt lat="37.331686" lon="-122.030656">
<time>2024-01-01T00:00:00Z</time>
</wpt>
<wpt lat="37.332686" lon="-122.031656">
<time>2024-01-01T00:00:10Z</time>
</wpt>
</gpx>xml
<?xml version="1.0"?>
<gpx version="1.1">
<wpt lat="37.331686" lon="-122.030656">
<time>2024-01-01T00:00:00Z</time>
</wpt>
<wpt lat="37.332686" lon="-122.031656">
<time>2024-01-01T00:00:10Z</time>
</wpt>
</gpx>Testing Authorization States
测试授权状态
Settings → Privacy & Security → Location Services:
- Toggle app authorization
- Toggle system-wide location services
- Test reduced accuracy
进入设置→隐私与安全性→定位服务:
- 切换应用的授权状态
- 切换系统级定位服务开关
- 测试降低精度模式
Console Filtering
控制台过滤
bash
undefinedbash
undefinedFilter location logs
过滤定位相关日志
log stream --predicate 'subsystem == "com.apple.locationd"'
---log stream --predicate 'subsystem == "com.apple.locationd"'
---Part 10: Swift Concurrency Integration
第十部分:Swift并发集成
Task Cancellation
任务取消
swift
let locationTask = Task {
for try await update in CLLocationUpdate.liveUpdates() {
if Task.isCancelled { break }
processUpdate(update)
}
}
// Later
locationTask.cancel()swift
let locationTask = Task {
for try await update in CLLocationUpdate.liveUpdates() {
if Task.isCancelled { break }
processUpdate(update)
}
}
// 后续取消任务
locationTask.cancel()MainActor Considerations
MainActor 注意事项
swift
@MainActor
class LocationViewModel: ObservableObject {
@Published var currentLocation: CLLocation?
func startTracking() {
Task {
for try await update in CLLocationUpdate.liveUpdates() {
// Already on MainActor, safe to update @Published
self.currentLocation = update.location
}
}
}
}swift
@MainActor
class LocationViewModel: ObservableObject {
@Published var currentLocation: CLLocation?
func startTracking() {
Task {
for try await update in CLLocationUpdate.liveUpdates() {
// 已在MainActor中,可安全更新@Published属性
self.currentLocation = update.location
}
}
}
}Error Handling
错误处理
swift
Task {
do {
for try await update in CLLocationUpdate.liveUpdates() {
if update.authorizationDenied {
throw LocationError.authorizationDenied
}
processUpdate(update)
}
} catch {
handleError(error)
}
}swift
Task {
do {
for try await update in CLLocationUpdate.liveUpdates() {
if update.authorizationDenied {
throw LocationError.authorizationDenied
}
processUpdate(update)
}
} catch {
handleError(error)
}
}Troubleshooting Quick Reference
故障排除快速参考
| Symptom | Check |
|---|---|
| No location updates | Authorization status, Info.plist keys |
| Background not working | Background mode capability, CLBackgroundActivitySession |
| Always auth not effective | CLServiceSession with |
| Geofence not triggering | Region count (max 20), radius (min ~100m) |
| Reduced accuracy only | Check |
| Location icon stays on | Ensure |
| 症状 | 检查项 |
|---|---|
| 无定位更新 | 授权状态、Info.plist键配置 |
| 后台定位不工作 | 后台模式权限、CLBackgroundActivitySession |
| 始终允许权限无效 | 使用 |
| 地理围栏未触发 | 区域数量(最多20个)、半径(最小约100米) |
| 仅能获取降低精度的定位 | 检查 |
| 定位图标持续显示 | 确保调用 |
Resources
资源
WWDC: 2023-10180, 2023-10147, 2024-10212
Docs: /corelocation, /corelocation/clmonitor, /corelocation/cllocationupdate, /corelocation/clservicesession
Skills: axiom-core-location, axiom-core-location-diag, axiom-energy-ref
WWDC:2023-10180, 2023-10147, 2024-10212
文档:/corelocation, /corelocation/clmonitor, /corelocation/cllocationupdate, /corelocation/clservicesession
技能:axiom-core-location, axiom-core-location-diag, axiom-energy-ref