Share visionOS experiences with nearby people
Audio & Video 进阶 0m

与附近的人共享 visionOS 体验

Share visionOS experiences with nearby people

2025年6月9日

在 Apple 官方观看视频

一句话判断

visionOS 26 的 SharePlay 终于支持同一房间的多人协作——窗口栏上一个分享按钮,就能让所有人看到同一个 app 在同一个位置,而且已有 SharePlay 代码零改动就能用。

这场 Session 讲了什么

visionOS 26 引入了 Nearby Window Sharing:每个窗口右侧新增一个分享按钮,点击后选择附近的人,窗口就会以相同位置和大小出现在所有人的空间里。窗口栏变绿表示正在共享。

核心体验:

  • 共享窗口在所有人面前出现在同一个物理位置
  • 任何人都可以移动窗口,移动对所有人可见
  • 手指靠近窗口时内容自动淡出,保证手势可见
  • 可以同时和 FaceTime 远程参与者共享(Spatial Persona 自动排列在附近参与者旁边)

已有 SharePlay app 零改动即可支持 nearby sharing。但 session 给了几个增强体验的 API:

  1. Share Menu 集成:用 ShareLink 把 GroupActivity 暴露到新的 Share 菜单。Immersive Space 没有窗口栏,需要自己提供按钮调用 activate()
  2. 检测附近参与者ParticipantState.isNearbyWithLocalParticipant 区分附近和远程参与者。
  3. 参与者 PoseParticipantState.pose 告诉你每个人在 ImmersiveSpace 场景里的位置,可以用来在每人旁边放置内容。
  4. AVPlayer 同步:visionOS 26 的 AVPlayer 精确同步附近参与者的音视频播放,解决回声问题。
  5. 多窗口关联.groupActivityAssociation modifier 选择哪个 WindowGroup 是 SharePlay 的主窗口。
  6. Shared World Anchors:ARKit 新增共享锚点,内容锚定到物理空间,仅和附近参与者共享。

值得深挖的点

  1. Shared World Anchors 是杀手级特性。之前 SharePlay 的内容是”跟着窗口走”的,现在可以锚定到物理空间。想象多人在同一个房间里协作摆放虚拟家具、在墙上画白板、或者一起看锚定在桌面上的 3D 模型。

  2. AVPlayer 同步是附近场景的刚需。因为人就在旁边,设备间微小的音频延迟都会被听到形成回声。visionOS 26 的 AVPlaybackCoordinator 精确处理了这个问题。

  3. 参与者 Pose 不是实时追踪的。它在分享开始、重新居中等关键事件后更新。不要拿它做需要实时位置的交互。

  4. Immersive Space 共享需要设置 supportsGroupImmersiveSpace,否则共享的是窗口而不是沉浸空间。

代码片段

把 GroupActivity 暴露到 Share 菜单:

struct BoardGameView: View {
    var body: some View {
        VolumetricWindowGroup {
            BoardGameScene()
        }
        // 隐藏的 ShareLink,让 Share 菜单能启动 SharePlay
        .shareLink(activity: BoardGameActivity(), isHidden: true)
    }
}

检测附近参与者:

for participant in session.activeParticipants {
    if participant.isNearbyWithLocalParticipant {
        // 这个人和我在同一个房间
        assignToSameTeam(participant)
    }
}

创建 Shared World Anchor:

// 检查共享锚点是否可用
for await availability in worldTracking.anchorSharingAvailabilityUpdates {
    if availability == .available {
        break
    }
}

// 创建共享锚点
let anchor = WorldAnchor(
    originFromAnchorTransform: furnitureTransform,
    sharedWithNearbyParticipants: true  // 关键参数
)
try await worldTracking.add(anchor)

最佳实践

  • 已有 SharePlay 代码先测试一下 nearby sharing 是否直接可用,大概率零改动就行。
  • Immersive Space 一定要保留一个非沉浸模式,让用户可以从 Share 菜单启动共享。
  • 用 participant pose 在每人旁边放 UI(记分板、工具栏),不要假设所有人都在窗口正前方。
  • 共享媒体用 AVPlayer + AVPlaybackCoordinator,不要自己做同步。
  • Shared World Anchor 的 identifier 在所有设备上一致,用它做同步标识符。
  • 共享锚点在 SharePlay 结束后不持久化,和普通 world anchor 不同。

还有什么值得关注

  • “Customize spatial Persona templates in SharePlay” 讲了 seat pose 和自定义座位安排。
  • “Coordinate media experiences with Group Activities” 补充了 AVPlaybackCoordinator 的 setup。
  • “Create a great spatial playback experience” 是 visionOS 媒体播放的基础。
  • “Explore enhancements to your spatial business app” 讲了企业 app 如何用自己的网络层配合 shared world anchors。
  • Defenderella by Rock Paper Reality 是 nearby sharing 的游戏 demo。
Audio & Video 空间计算