Highlight
Core Location 在 iOS 17 引入了
CLLocationUpdate类,用一行for try await代码替代了传统的 delegate 模式,原生支持 Swift Concurrency,并内置自动暂停/恢复机制来节省电量。
核心内容
以前获取位置更新要写一堆代码:创建 CLLocationManager、设置 delegate、实现 didUpdateLocations、手动调用 startUpdatingLocation() 和 stopUpdatingLocation()。代码分散在多个方法里,状态管理复杂,还要自己处理后台保活和电量优化。
Apple 今年推出了 CLLocationUpdate,把这一切压缩成了一行代码。它返回一个 AsyncSequence,直接用 for try await 遍历就能拿到位置更新。不需要 delegate,不需要手动启停,代码从分散的回调变成了线性的顺序逻辑。
更关键的是自动暂停/恢复。当设备静止一段时间后,系统会自动暂停更新,发送一个 isStationary == true 的标记。设备再次移动时自动恢复。这省去了开发者自己判断静止状态的麻烦,也减少了后台唤醒次数。
后台场景也做了简化。如果你的 app 有 Live Activity,后台位置更新自动生效。如果没有,创建一个 CLBackgroundActivitySession 就能保持后台能力,系统会显示蓝色位置指示条让用户知情。
详细内容
CLLocationUpdate 的基本用法
(00:27)获取位置更新现在只需要一行代码:
import CoreLocation
for try await update in CLLocationUpdate.liveUpdates() {
print("My current location: \(update.location)")
}
关键点:
CLLocationUpdate.liveUpdates()返回AsyncSequence,支持for try await- 每个
update包含location: CLLocation?和isStationary: Bool location为nil表示当前无可用位置,区别于停止更新isStationary为true时设备已静止,可以break跳出循环停止更新
使用预设配置
(04:41)liveUpdates() 接受一个可选的 LiveConfiguration 参数:
for try await update in CLLocationUpdate.liveUpdates(.fitness) {
print("Location: \(update.location)")
}
LiveConfiguration 包含以下预设:
.default— 默认配置.automotiveNavigation— 车载导航.otherNavigation— 其他导航.fitness— 运动健身.airborne— 航空
这些对应旧的 CLActivityType,迁移时选择对应配置即可获得相同的位置精度体验。
AsyncSequence 的过滤能力
(03:17)返回的 Updates 是 AsyncSequence,可以直接使用过滤操作:
let fastUpdate = try await CLLocationUpdate.liveUpdates()
.first { update in
guard let speed = update.location?.speed else { return false }
return speed > 200 // 200 米/秒,约 447 英里/小时
}
关键点:
first等过滤操作会阻塞直到匹配条件- 匹配成功后
AsyncSequence自动结束,无需手动停止 - 基于
horizontalAccuracy的过滤要小心,可能长时间无法匹配
后台位置更新
(06:04)最佳方式是配合 Live Activity。只要 Live Activity 处于活跃状态,app 就能在后台接收位置更新,无需额外配置。
如果没有 Live Activity,使用 CLBackgroundActivitySession:
class LocationManager {
var backgroundActivity: CLBackgroundActivitySession?
func startBackgroundUpdates() {
// 必须赋值给属性,不能用局部变量
backgroundActivity = CLBackgroundActivitySession()
Task {
for try await update in CLLocationUpdate.liveUpdates() {
print("Location: \(update.location)")
if update.isStationary {
break
}
}
}
}
func stop() {
backgroundActivity?.invalidate()
backgroundActivity = nil
}
}
关键点:
CLBackgroundActivitySession必须持有引用,dealloc 会自动 invalidate- app 的
UIBackgroundModes仍需包含location - 新的 session 只能从前台启动,后台只能 rejoin 已有的 session
自动暂停与恢复
(09:19)设备静止时,系统会自动暂停更新:
- 设备静止足够长时间 → 触发自动暂停
- 发送
isStationary = true的更新,location 非 nil - 设备再次移动 → 自动恢复
- 发送
isStationary = false的更新,继续递送位置
这让 app 无需自己判断静止状态,也避免了处理冗余位置数据。
App 生命周期与恢复
(10:39)后台运行期间,app 可能在以下状态间切换:
- 前台运行 → 后台运行:正常过渡
- 后台运行 → 挂起:无更新可递送时自动发生
- 挂起 → 后台运行:更新可用时自动恢复,无需操作
- 后台运行/挂起 → 终止:崩溃、用户关闭或系统回收资源
app 被终止后,系统在位置更新可用时会自动后台启动 app。此时需要在 application(_:didFinishLaunchingWithOptions:) 中重建 liveUpdates() 和 CLBackgroundActivitySession:
func application(_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// 重建后台 session(这是 rejoin,不是新建)
backgroundActivity = CLBackgroundActivitySession()
Task {
for try await update in CLLocationUpdate.liveUpdates() {
handleLocationUpdate(update)
}
}
return true
}
关键点:
- 重建操作必须在收到后台启动后立即执行
- 后台重建的
CLBackgroundActivitySession是 rejoin 已有 session,符合后台启动限制
核心启发
1. 运动追踪 App 的电量优化
- 做什么:用
CLLocationUpdate替换旧的CLLocationManagerdelegate 模式 - 为什么值得做:自动暂停/恢复机制让设备静止时停止耗电,无需自己写静止检测逻辑
- 怎么开始:把
locationManager.startUpdatingLocation()换成for try await update in CLLocationUpdate.liveUpdates(.fitness)
2. 外卖/打车实时位置共享
- 做什么:给骑手/司机端加上 Live Activity,配合
CLLocationUpdate实时上报位置 - 为什么值得做:Live Activity 让后台位置更新零配置生效,用户随时能在锁屏看到配送进度
- 怎么开始:先实现 Live Activity(参考 ActivityKit),然后直接在前台启动
CLLocationUpdate.liveUpdates()
3. 地理围栏 + 位置追踪的组合场景
- 做什么:用
CLMonitor监控地理围栏事件,用CLLocationUpdate追踪进入围栏后的详细轨迹 - 为什么值得做:两者结合可以精确知道”何时到达”和”在区域内做了什么”
- 怎么开始:先看 “Meet Core Location Monitor” session 了解
CLMonitor,再叠加CLLocationUpdate
4. 自动暂停的运动记录
- 做什么:利用
isStationary自动检测用户停下休息,暂停记录并提示 - 为什么值得做:以前要自己维护速度阈值和计时器,现在系统直接给出静止状态
- 怎么开始:在
for try await循环里检查update.isStationary,为true时暂停记录并显示”已暂停”
关联 Session
- Meet Core Location Monitor — 了解新的地理围栏和位置监控 API
- Meet ActivityKit — Live Activity 让后台位置更新更简单
- What’s new in Swift — Swift Concurrency 的新特性
评论
GitHub Issues · utterances