
-
与附近用户共享 visionOS 体验
了解如何为同一房间内佩戴 Apple Vision Pro 的用户打造共享体验。我们将展示如何在你的 App 中整合同播共享并充分利用 ARKit,介绍与附近 FaceTime 通话参与者共享窗口的流程有哪些更新,并介绍旨在实现流畅协作的全新 API。探索相关最佳实践,了解如何为身处同一空间的用户打造别具特色、易于发现且引人入胜的协作功能。
章节
- 0:00 - 简介
- 0:56 - 了解附近共享功能
- 4:21 - 构建附近活动
- 5:35 - 允许从共享菜单发起共享
- 9:15 - 针对附近参与者进行优化
- 10:37 - 相对于用户来放置内容
- 13:20 - 协调共享媒体播放
- 15:38 - 支持多个窗口
- 16:50 - 共享锚定内容
资源
- AVPlaybackCoordinator
- Building a guessing game for visionOS
- Configure your visionOS app for sharing with people nearby
- groupActivityAssociation(_:)
- init(originFromAnchorTransform:sharedWithNearbyParticipants:)
- worldAnchorSharingAvailability
相关视频
WWDC25
WWDC24
WWDC23
WWDC21
-
搜索此视频…
你好 我是 Connor visionOS FaceTime 团队的工程师 很高兴向大家介绍一项新功能 它将带来前所未有的共享与协作体验 在 visionOS 26 中 你可以与同一空间内的 附近用户共享 App 和体验 这样你就能和身边的人 一起在 Vision Pro 观看内容、聆听 音乐或通过喜爱的 App 展开协作 在这个视频中 你将学习 如何设计与开发 适用于多人共享场景的 App 首先 我会对这项功能 做一个简要概述 接着演示如何运用“同播共享” 为同一物理空间内的用户 构建交互式体验 最后指导你通过 ARKit 和 共享现实场景锚点技术 将共享内容精准锚定到 所处的现实空间中 首先 我将演示在 visionOS 26 中 如何与附近的人共享 我们重新设计了 App 共享方式 比以往更加直观易用 现在每个窗口栏右侧 都新增了一个按钮 轻点即可唤出共享菜单 你可以从附近人员列表中选择对象 轻松开启共享之旅 当有人发起共享时 共享窗口会精确出现在 发起者设定的空间位置 窗口栏会变成绿色 提示当前内容 正与同一空间的所有人共享 这种体验创造了一个共享情境 这正是让同空间协作 充满魔力的关键所在 由于共享窗口对所有人而言 都位于同一空间位置 可以像真的在房间里一样 进行讨论和指向操作并与 App 交互
系统会确保每个人看到的窗口 不仅位置相同 大小也完全一致
共享窗口出现后 任何参与者都可以移动它 它的移动会同步呈现在所有人面前 窗口还会自然朝向小组
你们甚至可以协同调整 App 的大小 或将它移动到共享环境中 当有人按住数码表冠重新定位时 App 会自动调回到 对所有人最合适的位置 如果有人指向窗口内容或伸手遮挡 内容会淡出 以确保这个用户始终可见
这种共享情境不仅限于同处一室的人 就近共享功能最令人振奋的特性之一 便是与 FaceTime 通话的深度整合 当你与附近的人共享 App 时 可随时发起 FaceTime 通话 邀请远程用户加入 实现跨空间的社交互动与协作 当远程用户通过 visionOS 加入时 他的空间自影像将呈现在你的空间中 这一功能将临场感提升至全新境界 让所有人仿佛真实共处同一空间
当用户以空间自影像身份加入时 系统会智能寻找最佳位置 将它与现场参与者自然排布
系统对空间自影像的位置安排 会根据共享窗口类型动态调整 例如当有人加入共享视体窗口时 系统会自动填补 视体内容周围的空间空缺 最终形成对现场与远程参与者 都很理想的空间布局 用户还可通过 iOS 或 macOS 等 任何支持 FaceTime 通话的平台 加入协作
加入后 他们的视频画面 会显示在共享窗口旁 实现 App 操作与 实时对话的无缝同步 默认情况下 窗口共享为 “仅查看”模式 即使对方未安装 App 也能参与 这不需要采用任何 App 但若想创建支持 同空间交互的共享体验 则需采用“同播共享” “同播共享”是跨 Apple 平台实现 FaceTime 通话协作体验的核心技术 支持“同播共享”的 App 可实现实时互动 让用户能一起观影、听音乐、 玩游戏、协同创作等 visionOS 上现有的“同播共享” App 可直接与附近用户共享 而无需任何更改 值得一提的是 “同播共享”最新推出了 专为同空间协作设计的增强功能
如果你是初次接触“同播共享” 强烈建议先观看 “使用群组活动打造个性化体验” 和“构建空间同播共享体验”视频 我将深入讲解这些视频中提到的概念 本部分将涵盖多个关键主题 帮助你打造出色的就近共享体验 首先 我会阐述如何将 “同播共享”活动展示在 新的“共享”菜单中 这是让用户 能轻松发起共享的重要入口 之后 你将了解 如何通过检测附近参与者 来优化同空间体验 并掌握基于参与者空间位姿的 内容布局技术 我们还将以 AVPlayer 为例 演示如何实现近距离共享媒体播放 确保视频音频的完美同步 最后 针对多窗口 App 我会逐步讲解如何选择 与“同播共享”关联的目标窗口 首先 你需要做的第一件事就是 将“同播共享”活动 集成至“共享”菜单 随着 visionOS 26 全新“共享”菜单的推出 App 共享变得前所未有的便捷 要充分发挥这一优势 你需通过 SwiftUI 或 UIKit API 将 GroupActivity 接入“共享”菜单 当用户轻点“共享”按钮时 即可激活 GroupActivity 并启动“同播共享” 对于视体窗口 只有当 App 已暴露活动时 才能使用“共享”菜单 以开发一款棋盘游戏 App 为例 当我去朋友家拜访时 希望通过 “同播共享”与他们一起玩棋盘游戏
首先 我为这款 App 创建了一个 名为 BoardGameActivity 的 简单的群组活动 GroupActivities 框架是 “同播共享”的技术基础 而定义一个 GroupActivity 是创建共享体验的第一步 我为游戏主场景配置了 呈现游戏界面的视体 WindowGroup 这是一个 SwiftUI App 为了将 BoardGameActivity 暴露至共享菜单 需要在视图层级中 添加 ShareLink 控件 我传入了我想要启动的 BoardGameActivity 并将它标记为隐藏 因为我不希望它影响我的 App 界面 当有人从“共享”菜单中 选择一个已暴露的活动时 系统会自动激活活动 并创建一个 GroupSession 这与手动调用 GroupActivity 的 activate() 方法效果相同
我可以通过观察 BoardGameActivity 上的会话 来获取这个自动创建的 GroupSession 然后 为了真正启动“同播共享” 我需要配置并加入这个创建的会话
现在用户就可以直接从 “共享”菜单开始共享我的 App 了 这些适用于窗口式或视体式 App 但如果你的共享体验使用了 沉浸式空间 那就需要额外考虑 如何确保“共享”菜单始终可访问 例如 我想把我的窗口式体验 变成一个放置在房间地板上的 全尺寸棋牌桌 周围还配有主题 3D 物体 让游戏体验更加真实 要实现这种效果 就需要将它置于 ImmersiveSpace 中 但现在我遇到了一个问题 在沉浸式空间中没有窗口栏 用户该如何共享我的 App 呢? 解决方案是 我可以提供一个自定义按钮 让用户无需依赖窗口或立体界面 就能启动共享 当用户点击这个按钮时 App 会调用 BoardGameActivity 的 activate() 方法 visionOS 26 有一项更新 即在调用 activate() 方法时 即使不在 FaceTime 通话中 系统也会自动弹出共享菜单 这一功能适用于窗口模式 和沉浸式空间 之后 你既可选择就近共享对象 亦可创建新的 FaceTime 通话会话 直接从 App 中开始共享体验
在我的 App 中 更优的解决方案是 继续保留非沉浸模式
这样用户可先通过 普通窗口的“共享”菜单发起协作 待所有成员加入后 再无缝过渡至沉浸空间
与先前一样 仍需加入 GroupSession 来启动“同播共享”功能 需要注意的是 我还必须从会话中获取系统协调器 并将 supportsGroupImmersiveSpace 设为 true 确保所有人的沉浸空间保持同步定位 确认 App 可以共享后 就可以着手为同空间用户 优化或定制体验了 为此 你可以直接通过 新版 SharePlay API 检测附近参与者 当用户在就近共享时发起 FaceTime 通话 这个功能就显得尤为重要 以我的棋盘游戏 App 为例 我想让同空间的玩家与从 FaceTime 通话加入的远程玩家同场竞技 我要检查哪些玩家共处同一物理空间 并主动推荐这些邻近玩家成为队友
为此 我需要区分附近参与者 与远程参与者
我先从之前加入的 GroupSession 开始 为了获取会话中参与者的信息 我会观察 GroupSession 上的 activeParticipants 发布者 从参与者状态中 检查新增的 isNearbyWithLocalParticipant 属性 若这个属性为 true 则表示参与者在我附近 需排除本地参与者自身 因为我只关注其他附近参与者
这样一来我就可以让 附近的参与者分配到同一队伍 与远程参与者进行对抗游戏 要为同空间用户打造卓越体验 还需考虑附近参与者 相对于 App 的位置关系 比如将内容放置在 他们身旁或面向他们的方位 新的 SharePlay API 在共享开始时 会精确告知每个人的空间位置 这里举个例子 此前我一直认为附近用户 只有在正对 App 时才会触发共享 但实际上 App 启动共享时 附近用户可能位于空间中的任意位置 App 会保持原位共享 不会自动对齐到用户视角 这一点对于沉浸式空间 App 尤其重要 因为你可能需要将内容 放置在参与者附近 而非固定在沉浸式空间的原点 在这个具体示例中 我想为沉浸式棋盘游戏 App 中 每位附近的玩家显示计分板
为此 首先需要确定附近参与者 相对于 ImmersiveSpace 场景的 位置关系 你可以通过 ParticipantState 新增 的 Pose 属性获取这些位置信息
和之前一样 我首先从 已加入的群组会话开始 要获取 localParticipant 的信息 我会访问会话中的系统协调器 然后观察系统协调器上 localParticipantState 的异步序列 获取到 localParticipantState 后 就能读取这个状态下的新位姿属性 这个属性会告诉我本地参与者相对于 ImmersiveSpace 场景的精确位置
位姿属性并不会 实时追踪参与者的位置 但会在关键事件后更新 例如当共享开始时 或当有人按住数码表冠 进行重新定位后 一旦获取到本地参与者的位姿 我就可以计算出计分板 相对于每位参与者的位置 使它正好显示在他们身旁
除了参与者的实际位姿外 你还可以获取他们的座位位姿 这是一个相对于 App 固定物理位置的标准坐标 若想深入了解座位位姿 及如何使用空间模板自定义座位布局 推荐观看“在同播共享中自定义 空间自影像模板”视频 利用这个视频中的信息 我不仅能通过读取座位位姿 实现更高级的功能 还能主动引导用户移动到 实体桌旁的实际座位区域 从而为他们推荐体验 App 内容 的最佳站位 如果你的 App 已使用座位位姿 且需根据用户实际空间位置投放内容 建议迁移至参与者位姿系统
此外 若涉及共享视频或音频体验 visionOS 26 已对 AVPlayer 进行升级 可为同处一地的用户协调播放进度 将共享媒体融入同一空间 会带来一系列独特的挑战 尤其当用户物理距离相近时 共享媒体可能导致 听到其他参与者设备的播放声 这种微小的音频延迟 会对所有邻近参与者 造成明显干扰 因此确保所有人实时同步 接收音视频内容至关重要 visionOS 26 新推出的 AVPlayer 与 AVPlaybackCoordinator 功能 可精准同步同一物理空间内 用户的音视频播放
为演示这项功能 我想在棋盘游戏 App 中 新增教学视频功能 用户可随时开启共享视频 学习游戏规则 所有参与者都将实现 同步的音视频播放体验 教学结束后 玩家即可立即应用所学知识开始游戏
在我的 App 中 我会创建一个 AVPlaybackCoordinator 并将它与 GroupSession 进行配置 这样一来 就可以确保同一空间内 所有用户的播放进度精准同步 在我的 App 中 这意味着每位用户 都能同步观看和聆听教学视频 既没有回声 也不会产生延迟
要了解如何为“同播共享”设置 AVPlaybackCoordinator 推荐观看“使用小组活动 协调媒体体验”视频 如果你是 visionOS 媒体 App 开发的新手 还可以观看“打造出色的 空间播放体验”视频 现在 我的 App 中的 音视频已实现完美同步 但新增的教学视频窗口 带来了一个新的待解决的问题 App 内现在同时打开了 多个 WindowGroup: 棋盘游戏的视体窗口和教学视频窗口 为此 我必须更明确地指定 在两个窗口同时打开时共享哪一个 visionOS 26 新的 SharePlay API 允许我通过视图修饰器 随时精确选择要与 “同播共享”关联的 WindowGroup 这为支持多窗口的 App 解锁了前所未有的控制能力
这是我的 App 中已有的 棋盘游戏 WindowGroup 要添加新的教学视频 我会创建第二个 WindowGroup 来承载视频视图 然后 可以在 WindowGroup 的 视图中添加新的 .groupActivityAssociation 视图修饰器
通过传入 primary 参数 给 .groupActivityAssociation 我向系统表明: 只要这个窗口处于打开状态 就将它作为共享窗口使用
现在 我的棋盘游戏 App 可以 切换到完全同步的共享视频 待玩家准备就绪后 又能切回游戏界面
期待看到大家充分利用这些改进 打造惊艳的社交体验 现在正是采用 “同播共享”的最佳时机 但 Group Activities 并非唯一 新增近距离共享 API 的框架 ARKit 在 visionOS 26 中也有所 更新 通过共享现实场景锚点 让用户能将共享内容 固定在相同的物理位置 在深入探讨之前 我需要先回顾沉浸式空间 和常规现实场景锚点的几个关键概念 当 App 采用 ImmersiveSpace 时 可以将内容自由放置在 用户房间的任何位置 这种模式非常适合呈现环绕式内容 但 ImmersiveSpace 并不保证 会固定在同一个物理位置 例如 当用户移动并按住数码表冠 进行重新定位时 整个沉浸式空间都会随之调整 这对多数用例都很适用 但若希望内容能长期固定在 物理空间中 就可能产生问题 ARKit 的现实场景锚点 为此提供了解决方案 通过现实场景锚点 App 可以将内容固定在 用户空间中的特定物理位置 系统会确保这些内容 始终精确锚定在原始位置 即使用户按住数码表冠 进行重新定位也不会偏移
想象这样一个 App 用户可以将虚拟家具 摆放在现实空间中 既能辅助创建房屋平面图 也能自由尝试各种设计布局 对于这类 App 而言 确保虚拟家具始终固定在 同一物理位置且不会 随时间推移发生漂移至关重要 要构建这个 App 我需要将内容精确定位于 沉浸空间的坐标原点附近 并通过现实场景锚点确保位置固定 首先 通过 ARKitSession 和 WorldTrackingProvider 进行初始化 并在会话中启动 WorldTrackingProvider 当需要为家具 App 添加新锚点时 我会在 ImmersiveSpace 中 为家具创建 具有特定变换矩阵的 WorldAnchor 并将它添加至 WorldTrackingProvider 最后 监听 WorldTrackingProvider 的 anchorUpdates 序列更新 这个序列将在新锚点成功添加时 触发回调 然后只需将家具模型 绑定至锚点下方即可完成配置!
如今处于同一物理空间的 用户可以共享 app 现实场景的重要性愈发凸显 当与附近用户共享时 物理空间将成为你们的共享情境 现实场景锚点 让开发者能够将物理空间 转化为共享情境 若要在共享时将共享内容 固定到特定物理位置 App 应使用新的 API 将锚点标记为 “可被附近参与者共享”状态 在“同播共享”会话期间 这个 API 允许 App 创建 自动与附近参与者 (且仅限于附近参与者) 共享的现实场景锚点 仅当 SharePlay 处于活跃状态时 才可创建共享锚点 与常规的现实场景锚点不同 共享锚点在会话结束后不会持久化
我将把这个功能集成至 先前的家具规划 App 现在 当任一用户 在房间中添加家具时 所有附近参与者都将 看到家具的生成 由此实现真正的 多人协同设计房间的沉浸体验 首先 在尝试创建 共享现实场景锚点前 需确保这个功能可用 我会观察 WorldTrackingProvider 的 newWorldAnchorSharingAvailability 状态 一旦状态变为可用 即表明 App 已与附近用户进行共享 我就可以创建共享现实场景锚点
创建共享现实场景锚点的流程 与常规现实场景锚点基本一致 当用户添加家具时 需在创建 WorldAnchor 时将 sharedWithNearbyParticipants 设为 true 随后 所有附近参与者的 WorldTrackingProvider 都会通过 anchorUpdates 序列 接收到这个新共享锚点 且这个锚点的唯一标识符 在所有设备上完全一致 你可通过读取并同步这个标识符 确保 App 能正确关联各设备上锚点对应的内容
现实场景锚点同样适用于企业级 App 即使不依赖“同播共享” 也可通过自有网络层实现 若你正在开发支持附近多人协作的 空间商务 App 建议观看“了解面向 空间商务 App 的增强功能” 视频以了解更多信息
就近共享的核心在于 与他人同处一室共赏内容 而借助共享现实场景锚点 你就能打造 充分利用共处空间的沉浸式体验
观看本视频后 请先思考如何通过“同播共享” 让你的 App 实现最佳互动共享体验 用户如何协同操作 App 内容 采用“同播共享”后 确保通过支持全新的共享菜单 让所有用户都能 轻松开启 App 共享体验 这是一个机会 让你将共享体验 置于系统 UI 可直接触达的位置 然后思考如何为各种受支持平台上的 近场与远场用户设计共享体验 请记住 共享功能同时支持 附近与远程参与者 你的 App 现在既能 连接同一房间内的用户 也能联动世界各地的使用者 因此务必全面考量这些应用场景 最后 请打造 能充分利用物理空间的体验 运用现实场景锚点技术 让虚拟内容在真实房间中 更具临场感和交互性 当这些功能协同运作时 将迸发无限可能 你可以在实体墙面上 开展协作白板会议 在客厅畅玩沉浸式游戏 或是将空间变成私人影院 与好友共度电影之夜 这种就近共享体验是一种 全新且强大的 让你与身边人协作互动的方式 希望你能创造出 让人们相聚时 倍感亲密的体验
-
-
6:21 - Expose an activity with GroupActivities and SwiftUI
// Expose an activity with GroupActivities and SwiftUI import SwiftUI import GroupActivities struct BoardGameActivity: GroupActivity, Transferable { var metadata: GroupActivityMetadata = { var metadata = GroupActivityMetadata() metadata.title = "Play Together" return metadata }() } struct BoardGameApp: App { var body: some Scene { WindowGroup { BoardGameView() ShareLink(item: BoardGameActivity(), preview: SharePreview("Play Together")) .hidden() } .windowStyle(.volumetric) } } struct BoardGameView: View { var body: some View { // Board game content } }
-
7:14 - Join a GroupSession with GroupActivities
// Join a GroupSession with GroupActivities func observeSessions() async { // Sessions are created automatically when the activity is activated for await session in BoardGameActivity.sessions() { // Additional configuration and setup // Join SharePlay session.join() } }
-
8:57 - Join and configure a GroupSession with GroupActivities
// Join a GroupSession with GroupActivities func observeSessions() async { // Sessions are created automatically when the activity is activated for await session in BoardGameActivity.sessions() { // Additional configuration and setup guard let systemCoordinator = await session.systemCoordinator else { continue } systemCoordinator.configuration.supportsGroupImmersiveSpace = true // Join SharePlay session.join() } }
-
9:59 - Check for nearby participants with GroupActivities
// Check for nearby participants with GroupActivities func observeParticipants(session: GroupSession<BoardGameActivity>) async { for await activeParticipants in session.$activeParticipants.values { let nearbyParticipants = activeParticipants.filter { $0.isNearbyWithLocalParticipant && $0 != session.localParticipant } } }
-
11:42 - Observe local participant pose with GroupActivities
// Observe local participant pose with GroupActivities func observeLocalParticipantState(session: GroupSession<BoardGameActivity>) async { guard let systemCoordinator = await session.systemCoordinator else { return } for await localParticipantState in systemCoordinator.localParticipantStates { let localParticipantPose = localParticipantState.pose // Place presented content relative to the local participant pose } }
-
15:54 - Associate a specific window with GroupActivities and SwiftUI
// Associate a specific window with GroupActivities and SwiftUI import SwiftUI import GroupActivities struct BoardGameApp: App { var body: some Scene { WindowGroup { BoardGameView() ShareLink(item: BoardGameActivity(), preview: SharePreview("Play Together")) .hidden() } .windowStyle(.volumetric) WindowGroup(id: "InstructionalVideo") { InstructionalVideoView() .groupActivityAssociation(.primary("InstructionalVideo")) } } } struct BoardGameView: View { var body: some View { // Board game content } } struct InstructionalVideoView: View { var body: some View { // Video content } }
-
18:27 - Create a world anchor with ARKit
// Create a world anchor with ARKit import ARKit class AnchorController { func setUp(session: ARKitSession, provider: WorldTrackingProvider) async throws { try await session.run([provider]) } func createAnchor(at transform: simd_float4x4, provider: WorldTrackingProvider) async throws { let anchor = WorldAnchor(originFromAnchorTransform: transform) try await provider.addAnchor(anchor) } func observeWorldTracking(provider: WorldTrackingProvider) async { for await update in provider.anchorUpdates { switch update.event { case .added, .updated, .removed: // Add, update, or remove furniture break } } } }
-
20:02 - Observe sharing availability with ARKit
// Observe sharing availability with ARKit func observeSharingAvailability(provider: WorldTrackingProvider) async { for await sharingAvailability in provider.worldAnchorSharingAvailability { if sharingAvailability == .available { // Store availability to check when creating a new shared world anchor } } }
-
20:24 - Create a shared world anchor with ARKit
// Create a shared world anchor with ARKit import ARKit class SharedAnchorController { func setUp(session: ARKitSession, provider: WorldTrackingProvider) async throws { try await session.run([provider]) } func createAnchor(at transform: simd_float4x4, provider: WorldTrackingProvider) async throws { let anchor = WorldAnchor(originFromAnchorTransform: transform, sharedWithNearbyParticipants: true) try await provider.addAnchor(anchor) } func observeWorldTracking(provider: WorldTrackingProvider) async { for await update in provider.anchorUpdates { switch update.event { case .added, .updated, .removed: // Add, update, or remove furniture. Updates with shared anchors from others! let anchorIdentifier = update.anchor.id } } } }
-
-
- 0:00 - 简介
在 visionOS 26 中,使用 FaceTime 通话的用户可以与附近佩戴 Apple Vision Pro 的用户共享 App 和体验。这意味着,你可以利用“同播共享”和 ARKit,在同一个物理空间内以协作的方式观看、聆听内容并进行互动。
- 0:56 - 了解附近共享功能
visionOS 26 中新增了一项共享功能,用户只需轻点窗口栏右侧的按钮,即可轻松地与附近的人共享 App。共享窗口会显示在相同的物理位置,供房间中的每个人使用,从而营造出共享情境,用户能够在其中像面对真实物体一样讨论、指点并与 App 进行交互。 系统可确保窗口在所有用户眼中都具有一致的外观和大小。任何人都可以移动或调整窗口大小,每位用户都能实时查看到这些更改。远程用户可以通过 visionOS 上的 FaceTime 通话加入共享会话,并以空间自影像的形式出现在共享空间中;如果是通过 iOS 或 macOS 加入,他们则会以视频影像的形式出现在共享窗口旁边,从而实现无论身在何处都能顺畅协作。
- 4:21 - 构建附近活动
visionOS 上现有的“同播共享”App 可直接与附近用户共享,而无需任何更改。不过,现在新增了一些功能,可以专门用于提升同一空间内用户的“同播共享”体验。这些功能包括:可在全新的“共享”菜单中直接发现“同播共享”活动;检测附近的参与者;根据参与者的空间位姿布局内容;同步媒体播放。
- 5:35 - 允许从共享菜单发起共享
在 visionOS 26 中,你可以通过使用 SwiftUI 或 UIKit API 公开 GroupActivity 以在 App 中启用“同播共享”功能。启用后,用户可以直接从新的“共享”菜单启动“同播共享”。对于视体窗口,必须公开活动才能使用“共享”菜单。 对于沉浸式空间,由于无法访问传统的“共享”菜单,你可以提供 App 内按钮来激活“共享”菜单。另一种方式是提供非沉浸式模式,让用户可以先通过“共享”菜单发起共享,在所有人加入会话后再切换到沉浸式模式。
- 9:15 - 针对附近参与者进行优化
使用 SharePlay API 识别 GroupSession 中的附近参与者。通过观察 activeParticipants 发布者并检查“isNearbyWithLocalParticipant”属性,可以区分本地用户和远程用户。这种方法可以实现一些功能,例如在游戏中自动将附近玩家组队,让他们可以与通过 FaceTime 通话加入的远程玩家一同进行线下对战。
- 10:37 - 相对于用户来放置内容
“ParticipantState”上新增的“位姿”属性为你提供了 App 会话中参与者的空间位置,让你能够将内容动态地放置在每位用户的旁边。这进一步提升了沉浸式体验,并支持更高级的功能,例如引导用户前往最佳的座位。
- 13:20 - 协调共享媒体播放
在 visionOS 26 中,AVPlayer 得到了增强,可以在同一物理空间中为用户同步音频和视频播放,从而解决了由音频延迟和回声引起的问题。这项新功能可实现无缝的共享媒体体验,让每位用户都能同时看到和听到内容。你可以使用“AVPlaybackCoordinator”来实现这种精确的同步。
- 15:38 - 支持多个窗口
通过 visionOS 26 中的新增 SharePlay API,你可以使用“groupActivityAssociation”视图修饰符指定 App 中的哪个“WindowGroup”与“同播共享”相关联。借助这个视图修饰符,你可以无缝切换共享内容,从而提升多窗口 App 内的使用体验。
- 16:50 - 共享锚定内容
ARKit 在 visionOS 26 中引入了共享现实场景锚点,使 App 能够将虚拟内容放置在固定的物理位置,并确保其在多个会话和不同用户之间持续可见。这种持续性对于协作 App 特别有用,因为在这些 App 中,需要保持将虚拟物体锚定在现实世界场景中。 你可以使用新的“sharedWithNearbyParticipants”参数在“同播共享”会话期间将现实场景锚点标记为“共享”,从而允许附近的参与者查看相同的虚拟内容并与之交互。使用“worldAnchorSharingAvailability”API 以确保共享功能可用。 此功能不仅适用于“同播共享”,还让商务 App 能够通过自定网络层使用共享锚点。 共享现实场景锚点为协作体验开辟了新的可能,例如虚拟白板、沉浸式游戏和共享电影之夜,使虚拟内容在现实世界中更加真实可感、互动性更强。