WWDC Quick Look 💓 By SwiftGGTeam
Meet Core Location for spatial computing

Meet Core Location for spatial computing

观看原视频

Highlight

Core Location 在 visionOS 上采用与 iOS 相同的权限模型和 API,但”在使用中”的定义基于用户的视线方向而非前台状态:头显单独使用时定位精度约 100 米,附近 iPhone 可将精度提升至手机级别;窗口应用在用户视线移开后会在短暂宽限期内停止接收位置更新。

核心内容

权限模型:熟悉但需重新理解

00:50)在 visionOS 上请求位置权限的方式与 iOS 完全一致。创建 CLLocationManager,调用 requestWhenInUseAuthorization(),并在 Info.plist 中设置 NSLocationWhenInUseUsageDescription 说明字符串。

02:14)用户看到的授权弹窗也与 iOS 类似:可以选择允许一次、使用时允许或拒绝,还可以选择精确或模糊定位。但这里的”使用时允许”在空间计算平台上有完全不同的含义。

02:52)关键原则:只在真正需要定位的上下文中请求权限。启动时就请求权限会降低用户授权的概率,也违背隐私设计原则。

定位精度:设备组合决定精度

04:04)visionOS 设备单独使用时的定位精度约为 100 米,与 Mac 相当。这足够用于查找附近餐厅、公园等场景。

04:24)但如果用户的 iPhone 在附近,两台设备之间的协同连接可以将定位精度提升到 iPhone 级别。这意味着你的应用需要根据当前精度调整行为——在 100 米精度下做精确导航没有意义。

“在使用中”的全新定义

05:02)这是 session 最核心的内容。在 iPhone 上,“在使用中”等同于”应用在前台”。但在 visionOS 上,这个概念完全不同。

05:33)对于全沉浸式应用,只要用户正在运行你的应用,就视为”在使用中”,可以获取位置更新。

05:56)对于窗口应用,Core Location 只有在用户”最近看过”(looked at)应用时才认为它在”使用中”。如果用户视线移开,应用会在短暂宽限期(几秒钟)后停止接收位置更新。

06:17)具体场景:

  • 用户没有与任何应用交互:两个应用都收不到位置更新
  • 用户看向左侧应用:左侧应用可以获取位置更新,右侧应用不行
  • 用户将两个窗口移到一起,能同时看到:两个应用都可以获取位置更新
  • 用户视线在左右应用间切换:短暂宽限期内两个应用都能获取更新

07:33)应用未运行时不会收到任何位置更新,monitoring API(如区域监听)的更新也不会被投递。这与 iOS 的后台行为有本质区别。

兼容模式下的行为

07:54)如果你的 iPhone 或 iPad 应用直接在 visionOS 上运行(兼容模式),需要注意以下变化:

  • 请求 Always 授权会被重定向为 WhenInUse 授权
  • Settings 中不会出现 Always 选项
  • 区域监听(CLMonitor/CLCircularRegion)不会收到事件
  • 后台位置更新不可用

如果你的 iOS 应用假设某些 API 始终可用,可能会在 visionOS 上出现意外行为。建议在发布前测试兼容模式下的表现。

详细内容

请求位置更新的代码

00:54)使用 CLLocationUpdate 获取实时位置更新:

import CoreLocation

actor LocationActor {
    func startUpdates() async {
        // 请求权限
        let manager = CLLocationManager()
        manager.requestWhenInUseAuthorization()
        
        // 获取实时位置更新
        for await update in CLLocationUpdate.liveUpdates() {
            if let location = update.location {
                print("Latitude: \(location.coordinate.latitude)")
                print("Longitude: \(location.coordinate.longitude)")
                print("Accuracy: \(location.horizontalAccuracy) meters")
            }
        }
    }
}

关键点:

  • CLLocationUpdate.liveUpdates() 返回异步序列,符合 Swift Concurrency 模式
  • 需要在 Info.plist 中设置 NSLocationWhenInUseUsageDescription
  • 检查 horizontalAccuracy 来判断当前精度是否满足需求

根据精度调整应用行为

func handleLocationUpdate(_ location: CLLocation) {
    let accuracy = location.horizontalAccuracy
    
    if accuracy <= 10 {
        // iPhone 级别精度,可以做精确导航
        showDetailedNavigation()
    } else if accuracy <= 100 {
        // 头显单独使用时的精度
        showNearbyPlaces()
    } else {
        // 精度较低,只显示大致区域
        showGeneralArea()
    }
}

视线感知的窗口应用设计

06:17)窗口应用需要适应视线驱动的位置更新模式:

import SwiftUI
import CoreLocation

struct LocationView: View {
    @StateObject private var locationModel = LocationModel()
    
    var body: some View {
        VStack {
            if let location = locationModel.lastLocation {
                Text("Current: \(location.coordinate.latitude), \(location.coordinate.longitude)")
                Text("Accuracy: ±\(Int(location.horizontalAccuracy))m")
                    .foregroundColor(accuracyColor(location.horizontalAccuracy))
            } else {
                Text("Looking away - location updates paused")
                    .foregroundColor(.secondary)
            }
        }
        .task {
            await locationModel.startMonitoring()
        }
    }
    
    func accuracyColor(_ accuracy: CLLocationAccuracy) -> Color {
        if accuracy <= 10 { return .green }
        if accuracy <= 100 { return .yellow }
        return .orange
    }
}

@MainActor
class LocationModel: ObservableObject {
    @Published var lastLocation: CLLocation?
    
    func startMonitoring() async {
        let manager = CLLocationManager()
        manager.requestWhenInUseAuthorization()
        
        for await update in CLLocationUpdate.liveUpdates() {
            if let location = update.location {
                self.lastLocation = location
            }
        }
    }
}

关键点:

  • 使用 .task 修饰符在视图出现时启动位置监听
  • 当用户视线移开时,更新会暂停,UI 应显示相应状态
  • @MainActor 确保 UI 更新在主线程执行

核心启发

  1. 设计视线感知的定位体验

    • 做什么:为 visionOS 窗口应用设计适应视线驱动位置更新的 UI,明确显示定位活跃状态
    • 为什么值得做:用户视线移开时位置更新会暂停,UI 需要让用户理解这个行为,避免困惑
    • 怎么开始:在视图中添加位置状态指示器,使用 .task 管理位置更新的生命周期,处理更新暂停时的 UI 状态
  2. 根据精度动态调整功能

    • 做什么:根据 horizontalAccuracy 的值动态调整应用提供的功能粒度
    • 为什么值得做:头显单独使用时 100 米精度与 iPhone 配合时的米级精度差异巨大,同样的 UI 在两种精度下体验完全不同
    • 怎么开始:在获取位置更新时检查精度值,为不同精度范围设计不同的功能层级和 UI 表现
  3. 测试兼容模式下的位置行为

    • 做什么:在 visionOS 模拟器和设备上测试现有 iOS 应用在兼容模式下的位置相关功能
    • 为什么值得做:Always 授权被降级、区域监听不工作、后台更新不可用,这些变化可能导致现有应用行为异常
    • 怎么开始:在 Xcode 中选择 visionOS 模拟器运行现有 iOS 应用,测试位置请求、区域监听和后台行为
  4. 利用设备协同提升定位体验

    • 做什么:设计功能时考虑 iPhone 在附近的高精度场景和头显单独使用的低精度场景
    • 为什么值得做:两种场景都是真实用户会遇到的,应用应该在两种情况下都提供合理的体验
    • 怎么开始:在 UI 中提示用户将 iPhone 放在附近以获得更精确的定位,同时为低精度场景设计降级方案

关联 Session

评论

GitHub Issues · utterances