Support immersive video playback in visionOS apps
2025年6月9日
一句话判断
visionOS 26 的沉浸式视频播放现在覆盖了 180/360/Wide-FOV + Spatial Video + Apple Immersive Video 全格式。Quick Look 零代码支持,AVKit 有新 API 做精确体验控制,RealityKit 给了你完全自定义的能力。选哪个框架取决于你要多少控制权。
这场 Session 讲了什么
Jamal 和 Michael 分两部分讲了三个框架的沉浸式视频播放能力。
Quick Look——最简单的路径。 PreviewApplication 和 QLPreviewController 在 visionOS 26 自动支持所有新格式(APMP 180/360/Wide-FOV + Apple Immersive Video)。已经接入 Quick Look API 的 app 不需要改任何代码就能获得支持。QLPreviewController 新增了对 spatial photos 和 videos 的支持。
AVKit——可控的体验。 AVExperienceController 是核心。三种体验模式:
- Expanded: 全屏播放。新增
AutomaticTransitionToImmersive配置,设为.none可以让沉浸式内容以 portal 形式展示而非自动进入沉浸模式。 - Immersive: 完全沉浸。用 Configuration API 指定 placement(在哪个 window scene 上方)。如果 AVPlayerViewController 已经在 view hierarchy 中,系统会自动推断 placement。
- Delegate Protocol: 三个回调——
didChangeAvailableExperiences(内容类型变化时哪些体验可用)、prepareForTransitionUsing(即将转场前的最后准备)、didChangeTransitionContext(转场完成)。
舒适度检测: Quick Look 和 AVKit 会自动检测 APMP 视频中的高运动量,必要时降低沉浸度。用户可以在系统设置中调整行为偏好。
RealityKit——完全自定义。 VideoPlayerComponent 是核心组件,支持三种 immersive mode:
- Portal: 门户模式,在窗口中展示。
- Progressive: 渐进模式,用户用 Digital Crown 调节沉浸度(iOS 26 新增)。100% 时等同于 full immersive。
- Full: 完全沉浸。
Spatial video 的特殊处理: 有独立的 desiredSpatialVideoMode 属性。.spatial 模式提供完整的空间样式(类似 Photos app 的效果),.screen 是传统立体渲染。Immersive spatial video 不是 head-locked 的,需要设置实体位置。用 mixed ImmersionStyle + immersiveEnvironmentBehavior(.coexist) 让 spatial video 在 passthrough 和系统环境中都能渲染。
事件系统: ImmersiveViewingModeDidChange(模式切换)、ImmersiveViewingModeWillTransition/DidTransition(动画转场期间控制 UI 可见性)、VideoComfortMitigationDidOccur(舒适度调节信号)、ContentTypeDidChange(视频类型变化)。
值得深挖的点
Progressive 是 APMP 和 Apple Immersive Video 的推荐模式。 为什么?因为它支持 comfort mitigation(系统可以自动降低沉浸度),而 full immersive 不支持。对 APMP 内容来说这很重要——180/360 视频的运动量可能很大。
AVExperienceController 的 Expanded 配置是个隐藏技巧。 设 AutomaticTransitionToImmersive = .none 后,沉浸式内容会以 portal 形式呈现在 Expanded 播放器中。用户不会自动进入沉浸模式,但可以选择手动进入。这适合”先预览再决定是否沉浸”的场景。
Spatial video 的 ImmersiveSpace 必须用 mixed ImmersionStyle。 不像其他沉浸式视频用 progressive/full,spatial video 的沉浸模式是固定尺寸渲染在 passthrough 之上。如果想让它也能在系统环境中显示,加 immersiveEnvironmentBehavior(.coexist)。
VideoPlayerComponent 的 mesh 高度默认 1 米。 在 portal 模式下如果你的 window scene 不到 1 米高,会被裁剪。用 GeometryReader3D 获取窗口尺寸后统一缩放 X 和 Y 保持宽高比。
代码片段
RealityKit 中配置 progressive 沉浸式 180 视频:
struct ProgressiveVideoView: View {
let player: AVPlayer
var body: some View {
RealityView { content in
let component = VideoPlayerComponent(avPlayer: player)
component.desiredImmersiveViewingMode = .progressive
let entity = Entity()
entity.components.set(component)
content.add(entity)
}
}
}
// ImmersiveSpace 必须用 progressive ImmersionStyle
ImmersiveSpace(id: "video") {
ProgressiveVideoView(player: player)
}
.immersionStyle(selection: .constant(.progressive), in: .progressive)
Spatial video portal + immersive 切换:
// Portal 模式
let component = VideoPlayerComponent(avPlayer: player)
component.desiredViewingMode = .stereo
component.desiredSpatialVideoMode = .spatial
component.desiredImmersiveViewingMode = .portal
entity.scale = SIMD3(repeating: 0.4) // 适应窗口
// 切换到 immersive(不需要 scale,组件自动控制)
component.desiredImmersiveViewingMode = .full
// ImmersiveSpace 配置
ImmersiveSpace(id: "spatialVideo") {
SpatialVideoView(player: player)
}
.immersionStyle(selection: .constant(.mixed), in: .mixed)
.immersiveEnvironmentBehavior(.coexist)
AVKit 禁用自动沉浸过渡:
let vc = AVPlayerViewController()
vc.player = player
let controller = vc.experienceController
try await controller.setRecommendedExperiences()
var config = controller.configuration
config.automaticTransitionToImmersive = .none
controller.configuration = config
try await controller.transition(to: .expanded)
最佳实践
根据需要的控制程度选框架。 只想展示 → Quick Look。需要标准播放控件和自动过渡 → AVKit。需要自定义 UI、游戏集成或特殊渲染逻辑 → RealityKit。
Always match desiredImmersiveViewingMode with ImmersionStyle。 portal 对应 WindowGroup 或 mixed ImmersionStyle。progressive 对应 progressive ImmersionStyle。full 对应 mixed ImmersionStyle(spatial video)或 progressive/full ImmersionStyle(APMP/AIV)。
处理 mode transition 事件。 ImmersiveViewingModeWillTransition 和 DidTransition 之间应该隐藏可能与视频冲突的 UI 元素,减少运动和立体冲突。
Comfort mitigation 事件不需要你做任何事。 VideoComfortMitigationDidOccur 只是一个信号,告诉你系统做了什么。但你应该在 UI 上体现变化(比如告知用户”已降低沉浸度”)。
还有什么值得关注
- Quick Look 的自动支持意味着如果你的 app 已经用了
PreviewApplication或QLPreviewController,不需要改代码就能播放新的沉浸式格式。 - RealityKit 的
ContentTypeDidChange事件可以用来动态调整 UI——比如检测到是 APMP 内容时显示沉浸度控制条。 - 配套视频:“Learn about the Apple Projected Media Profile”(Session 297)详细讲解了 APMP 的格式规范和编码参数。
- Vision Pro 上推荐的编码参数:HEVC Main/Main 10, 4:2:0, 单目 8K 30fps / 双目 4K 30fps, 峰值码率不超过 150Mbps。