WWDC Quick Look 💓 By SwiftGGTeam
What's new in Nearby Interaction

What's new in Nearby Interaction

观看原视频

Highlight

Apple Location Technologies 团队的 Jon Schoenberg 介绍了 Nearby Interaction 框架在 iOS 16 中的两大新功能:ARKit 增强模式和后台会话。


核心内容

Nearby Interaction 原来解决的是“附近设备在哪里”。它依赖 U1 芯片和 Ultra Wideband(超宽带)测距,让两台设备或一台设备与配件之间获得距离和方向。2020 年支持两台 iPhone,2021 年扩展到 Apple Watch 和第三方 UWB 配件。

这个模型适合用户拿着手机主动寻找目标。问题出在两个地方。第一,UWB 的方向信息有视场角和遮挡限制,用户可能转到某个角度后拿不到稳定方向。第二,App 进入后台或锁屏后,正在运行的 NISession 会暂停,配件无法继续完成无感交互。

iOS 16 的更新围绕这两个问题展开。Camera assistance 把 ARKit 计算出的设备轨迹交给 Nearby Interaction,用来扩大有效视场并生成更稳定的方向信息。Accessory background sessions 则允许和 Bluetooth LE 配对的 UWB 配件在 App 后台继续运行 Nearby Interaction 会话。

Session 里的博物馆示例很具体:用户选择下一件展品后,App 发现展品旁边的 UWB 配件,提示用户左右扫动手机,然后显示箭头、判断目标是否在身后,并把 AR 内容叠到展品位置上。这个体验以前要自己协调 UWB、ARKit、蓝牙和前后台状态。现在 Nearby Interaction 把关键路径收进框架里。


详细内容

开启 ARKit 增强模式

04:47)如果 App 已经有一个接收 NIDiscoveryToken、创建配置、运行 NISession 的流程,开启 ARKit 增强模式只需要在 NIConfiguration 的子类上设置 isCameraAssistanceEnabled。这个能力同时支持 Apple 设备之间,以及 Apple 设备和第三方 UWB 配件之间的交互。

// 示意代码:session 没有提供完整代码片段,以下只展示 transcript 点名的 API 流程。
let configuration = /* App 既有流程:用 NIDiscoveryToken 创建 NIConfiguration 子类 */
configuration.isCameraAssistanceEnabled = true

let session = NISession()
session.delegate = self
session.run(configuration)

关键点:

  • NIDiscoveryToken 来自 nearby peer,App 用它创建 NIConfiguration 的子类。
  • isCameraAssistanceEnabled 是 iOS 16 新增属性,设置为 true 后启用 camera assistance。
  • NISession 仍然是 Nearby Interaction 的会话入口。
  • run(configuration) 启动会话;camera assistance 会让框架自动创建并运行一个内部 ARSession

05:27)框架自动创建的 ARSession 运行在 App 进程里,所以 App 必须在 Info.plist 里提供相机使用说明。这个说明要告诉用户为什么寻找附近物体需要相机。

<!-- Info.plist:示意配置,文案应按 App 场景改写。 -->
<key>NSCameraUsageDescription</key>
<string>使用相机来提高附近物体方向判断并显示空间指引。</string>

关键点:

  • NSCameraUsageDescription 是系统相机权限说明键。
  • camera assistance 会用到 ARKit,因此会触发相机权限要求。
  • 文案要解释“寻找附近物体”和“相机”之间的关系,避免用户看到权限弹窗时困惑。

和现有 ARKit 体验共享 ARSession

06:19)一个 App 同一时间只能运行一个 ARSession。如果 App 已经有 ARKit 体验,不能再让 Nearby Interaction 自动创建第二个会话。做法是在 NISession.run 之前调用新的 setARSession,把 App 自己创建的 ARSession 交给 Nearby Interaction。

// 示意代码:SwiftUI/ARView 场景下共享底层 ARSession。
let niSession = NISession()
let arSession = arView.session

niSession.setARSession(arSession)
niSession.run(configuration)

关键点:

  • arView.session 代表 App 现有 ARKit 视图里的底层 ARSession
  • setARSession 必须在 NISession.run 之前调用。
  • 调用后,Nearby Interaction 不会再自动创建内部 ARSession
  • 这样 ARKit 画面和 Nearby Interaction 的 camera assistance 可以并行使用同一个轨迹数据来源。

07:16)直接管理 ARSession 时,Apple 要求用 ARWorldTrackingConfiguration 运行,并按指定方式设置配置:worldAlignmentgravity,关闭 collaboration 和 user face tracking,initialWorldMapnil,delegate 的 sessionShouldAttemptRelocalization 返回 false

// 示意代码:只列出 transcript 明确要求的配置项。
let arConfiguration = ARWorldTrackingConfiguration()
arConfiguration.worldAlignment = .gravity
arConfiguration.isCollaborationEnabled = false
arConfiguration.userFaceTrackingEnabled = false
arConfiguration.initialWorldMap = nil

arSession.run(arConfiguration)

关键点:

  • ARWorldTrackingConfiguration 是共享 ARSession 时的运行配置。
  • .gravity 让世界坐标按重力方向对齐。
  • collaboration 和 user face tracking 必须关闭。
  • initialWorldMap 必须为 nil
  • 如果配置不符合要求,NISessionDelegatedidInvalidateWith 会收到新的 NIError.invalidARConfiguration

使用新的空间输出属性

08:21)App 继续通过 NISessionDelegatedidUpdateNearbyObjects 接收 nearby object 更新。开启 camera assistance 后,NINearbyObject 新增两个属性:horizontalAngleverticalDirectionEstimate。它们和原来的 distance、direction 一起描述设备到附近物体的空间关系。

// 示意代码:处理 transcript 提到的可选空间属性。
func session(_ session: NISession, didUpdate nearbyObjects: [NINearbyObject]) {
    guard let object = nearbyObjects.first else { return }

    // distance 可用于显示米级距离。
    let distance = object.distance

    // direction 可用于 3D 指向;不可用时,可退回到 horizontalAngle。
    let direction = object.direction
    let horizontalAngle = object.horizontalAngle

    // verticalDirectionEstimate 使用前要排除 unknown。
    let vertical = object.verticalDirectionEstimate
}

关键点:

  • distance 以米为单位,transcript 将它定义为用户设备和附近物体之间的关键空间关系之一。
  • direction 是从当前设备指向附近物体的 3D vector,可能为 nil
  • horizontalAngle 是水平方向上的 1D 弧度角;当 3D direction 不能解析时,它仍可能可用。
  • verticalDirectionEstimate 是定性垂直关系,可能是 same、above、below、aboveOrBelow 或 unknown。
  • 使用 verticalDirectionEstimate 前要检查 unknown,避免把不确定状态显示成楼层指引。

把附近物体放进 AR 世界

11:39)iOS 16 在 NISession 上增加了 worldTransform helper。它返回 ARKit 坐标空间里的 transform,用来表示某个 nearby object 在物理环境中的位置。Session 演示里浮在展品位置上的球体,就是用它放进 AR 场景的。

// 示意代码:使用 worldTransform 放置 AR 内容。
if let transform = niSession.worldTransform(for: nearbyObject) {
    // 将 AR 标记放到 transform 对应的位置。
} else {
    // 提示用户在水平和垂直方向扫动设备。
}

关键点:

  • worldTransformNISession 上的新 helper method。
  • 返回值位于 ARKit 的 coordinate space。
  • 当 transform 不可用时返回 nil
  • 用户需要在水平和垂直方向充分扫动设备,camera assistance 才能收敛到可用 transform。
  • transform 对体验重要时,session 建议提示用户采取动作。

用算法收敛状态指导用户

13:11)为了让 App 解释为什么 horizontalAngleverticalDirectionEstimateworldTransform 暂时不可用,NISessionDelegate 新增 didUpdateAlgorithmConvergence。它会返回 NIAlgorithmConvergence 和一个可选的 NINearbyObject。只有开启 camera assistance 时,这个 delegate 才会调用。

// 示意代码:根据收敛状态给用户提示。
func session(_ session: NISession,
             didUpdateAlgorithmConvergence convergence: NIAlgorithmConvergence,
             for nearbyObject: NINearbyObject?) {
    switch convergence.status {
    case .converged:
        showReadyState()
    case .unknown:
        showPreparingState()
    case .notConverged(let reasons):
        showGuidance(for: reasons)
    }
}

关键点:

  • NIAlgorithmConvergence 有一个 status 属性。
  • statusNIAlgorithmConvergenceStatus,表达算法是否已经 converged。
  • nearbyObjectnil 时,收敛状态属于整个 session;不为 nil 时才对应具体物体。
  • notConverged 带有 reasons 数组,App 可以按原因给出动作提示。
  • reason 可能包括总运动不足、水平扫动不足、垂直扫动不足、光照不足。
  • 多个 reason 可以同时存在,session 建议按 App 需要顺序引导用户。

按设备能力裁剪体验

16:23)原来的 NISession.isSupported 只回答设备是否支持 Nearby Interaction。iOS 16 新增 NISession.deviceCapabilities,返回 NIDeviceCapability,让 App 分别检查精确测距、方向测量和 camera assistance。

// 示意代码:按能力选择 UI。
let capabilities = NISession.deviceCapabilities

guard capabilities.supportsPreciseDistanceMeasurement else {
    showUnsupportedState()
    return
}

if capabilities.supportsCameraAssistance {
    enableARGuidanceMode()
} else if capabilities.supportsDirectionMeasurement {
    enableDirectionOnlyMode()
} else {
    enableDistanceOnlyMode()
}

关键点:

  • NISession.deviceCapabilities 取代只看 isSupported 的做法。
  • supportsPreciseDistanceMeasurement 至少等价于旧的支持性检查。
  • supportsDirectionMeasurement 表示设备是否能给出方向测量。
  • supportsCameraAssistance 表示设备是否支持 ARKit 增强模式。
  • session 特别提醒要保留 distance-only 体验,以支持 Apple Watch。

在后台运行配件会话

18:03)以前 App 进入后台或用户锁屏后,运行中的 NISession 会暂停。iOS 16 的 accessory background sessions 允许 App 利用 Core Bluetooth 后台能力,和已配对的 Bluetooth LE UWB 配件启动并延续 Nearby Interaction 会话。

概念流程:
1. 从配件收到 Ultra Wideband configuration data。
2. 从已配对的 Bluetooth LE 连接中取得该配件的 Bluetooth peer identifier。
3. 用这两份数据创建 NINearbyAccessoryConfiguration。
4. 用这个配置运行 NISession。

关键点:

  • Ultra Wideband configuration data 是配件通过数据通道发送给 App 的配置数据。
  • Bluetooth peer identifier 来自已配对的 Bluetooth LE 配件。
  • transcript 只说明新的 initializer 会接收这两份数据:UWB configuration data 和 Bluetooth peer identifier;没有给出 Swift 参数标签。
  • 配件必须已经通过 Bluetooth LE paired。
  • 配件还必须实现新的 Nearby Interaction GATT service,让 iOS 验证 Bluetooth identifier 和 UWB configuration 之间的关联。

22:15)Nearby Interaction GATT service 里有一个加密 characteristic:Accessory Configuration Data。它包含同一份 UWB configuration data。App 不能直接读取这个 characteristic;iOS 用它验证配件的蓝牙身份和 Nearby Interaction 会话是否匹配。

// 示意代码:后台会话需要的 App 配置项。
// Info.plist UIBackgroundModes:
// - nearby-interaction
// - bluetooth-central

关键点:

  • nearby-interaction 对应 session 里提到的 Nearby Interaction background mode。
  • bluetooth-central 对应 Xcode 能力里的 “Uses Bluetooth LE accessories”。
  • App 要能在后台连接配件,因此还要实现 Core Bluetooth 的后台连接和状态恢复流程。
  • 触发 LE pairing 会显示用户确认弹窗,session 建议放在 setup flow 或用户明确要交互的时刻。

25:35)后台会话有一个关键限制:App 在后台不会收到 didUpdateNearbyObjects callback,也不会获得运行时间。NISession 会继续运行,UWB measurements 会到达配件。因此,后台动作必须在配件端根据测量结果执行。

// 示意流程:后台期间由配件消费 UWB measurements。
// App: 建立后台 NISession,并把 sharable configuration 发给配件。
// Accessory: 接收 UWB measurements。
// Accessory: 根据距离或方向触发动作,例如开灯、播放音乐或解锁 eBike。
// App: 只在重要交互时由配件唤起,例如展示通知。

关键点:

  • App 后台期间,NISession 不会暂停。
  • App 后台期间,didUpdateNearbyObjects 不会回调到 App。
  • 配件端会收到 UWB measurements,并应直接决定用户动作。
  • 为了省电,session 建议只在重要用户交互时从配件向 App 发送数据。

核心启发

  • 做什么:博物馆或展厅的展品导航。 为什么值得做: camera assistance 能让距离、方向、水平角和垂直关系更稳定,适合引导用户走向静止物体。 怎么开始: 给每个展品放置 UWB 配件,在 App 中开启 isCameraAssistanceEnabled,用 horizontalAngle 画箭头,用 worldTransform 放置 AR 标记。

  • 做什么:多楼层寻物 App。 为什么值得做: verticalDirectionEstimate 提供 same、above、below、aboveOrBelow 这类楼层级提示,比只显示距离更适合室内寻找。 怎么开始:didUpdateNearbyObjects 中同时读取 distanceverticalDirectionEstimate,先提示楼层关系,再显示水平导航。

  • 做什么:智能音箱的入屋自动播放。 为什么值得做: accessory background sessions 允许 UWB 配件在 App 后台继续收到测量结果,适合 hands-free 场景。 怎么开始: 让音箱通过 Bluetooth LE paired,实现 Nearby Interaction GATT service,用新的 NINearbyAccessoryConfiguration initializer 绑定 UWB 数据和 CBPeripheral.identifier,在配件端处理测量结果。

  • 做什么:电动自行车靠近解锁。 为什么值得做: 用户不必打开 App;配件可以在后台会话中根据 UWB measurements 判断用户是否真正靠近。 怎么开始: App 负责配对、后台连接和会话配置;自行车端根据测量结果执行解锁,并只在需要提示用户时通知 App。

  • 做什么:能力自适应的空间交互 UI。 为什么值得做: 不是所有设备都支持方向测量或 camera assistance,Apple Watch 还需要 distance-only 体验。 怎么开始: 启动前读取 NISession.deviceCapabilities,按 supportsCameraAssistancesupportsDirectionMeasurementsupportsPreciseDistanceMeasurement 分别选择 AR 指引、方向指引或纯距离模式。


关联 Session

评论

GitHub Issues · utterances