Highlight
visionOS 上的视频播放完全复用现有的 AVFoundation + AVKit 代码,AVPlayerViewController 通过 RealityKit 渲染实现空间沉浸体验,支持 3D 视频、空间音频和自动环境调暗,开发者只需确保使用 visionOS SDK 编译并让播放器填满窗口。
核心内容
现有代码直接可用
你已经用 AVPlayerViewController 在 iOS 上播放视频了吗?那你在 visionOS 上几乎不需要改代码。
(00:42)AVFoundation 负责所有底层工作:流媒体、解析、解码、同步。AVKit 的 AVPlayerViewController 在 visionOS 上被增强为使用 RealityKit 渲染,视频可以无缝融入用户周围的空间环境,音频也会响应空间位置变化。
兼容的 iOS App(用 iOS SDK 编译)会获得 iOS 兼容的播放体验。要获得完整的空间增强体验,Xcode 项目必须使用 visionOS SDK 编译。
三行代码启动空间影院
(02:23)使用方式与 iOS/tvOS 完全相同:
import AVFoundation
import AVKit
let playerViewController = AVPlayerViewController()
playerViewController.player = AVPlayer(url: videoURL)
present(playerViewController, animated: true)
关键点:
- 先设置 player 到 view controller,再创建 player item,这样 player 在加载媒体前就知道如何显示,提升性能
- 让 AVPlayerViewController 填满窗口以获得最佳沉浸体验
- SwiftUI 中用 UIViewControllerRepresentable 包装
空间播放体验
(03:27)App 启动后,一块大屏幕出现在用户面前,房间自动调暗营造观影氛围。移动时屏幕保持在原位,音频锚定在屏幕上。看向屏幕并轻捏手指显示播放控件,控件悬浮在视频前方。用 Digital Crown 调节音量,或打开沉浸式环境(如影院环境)。
播放控件详解
(04:48)visionOS 的播放控件包括:
- 右上角:音量控制(也可通过 Digital Crown 调节)
- 左下角:播放/暂停、后退/快进
- 底部中间:进度条拖拽
- 右下角:更多选项(播放速度、音轨选择、字幕、调暗效果)
调暗效果(Dimming Effect)可以关闭,让用户在观看视频时也能看到周围环境。
高级功能
(05:49)
缩略图拖拽:HLS 流包含 I-frame only playlist(Trick Play track)时,拖拽进度条会自动显示缩略图。推荐 145 像素宽的小 Trick Play track。
插播内容(Interstitials):支持在时间线中插入 logo、回顾或广告。通过 AVPlayerInterstitialEventController 编程配置,或在 HLS 流中描述。
上下文操作(Contextual Actions):添加”跳过片头”、“播放下一集”等自定义按钮。
自定义信息面板:显示内容元数据或推荐相关内容。
沉浸式空间(Immersive Space)
(07:13)App 可以创建 Immersive Space,视频屏幕会自动移入该空间,锚定在固定大小和位置,保证最佳观看角度。控件会脱离屏幕移近一些,方便交互。
@main
struct MoviePlayingApp: App {
@State private var immersionStyle: ImmersionStyle = .full
var body: some Scene {
WindowGroup {
ContentView()
}
ImmersiveSpace(id: "theater") {
TheaterView()
}
.immersionStyle(selection: $immersionStyle, in: .full)
}
}
struct ContentView: View {
@Environment(\.openImmersiveSpace) var openImmersiveSpace
var body: some View {
PlayerView()
.onAppear {
Task {
await openImmersiveSpace(id: "theater")
}
}
}
}
关键点:
ImmersiveSpace定义 3D 内容场景openImmersiveSpace打开空间后,AVPlayerViewController 自动将视频屏幕移入- 确保 Immersive Space 设计能容纳播放器停靠
详细内容
视频展示方式对比
(12:32)visionOS 提供多种视频展示方式,各有适用场景:
| 方式 | API | 适用场景 | 3D 视频 | 播放控件 | 系统集成 |
|---|---|---|---|---|---|
| 全屏播放器 | AVPlayerViewController(填满窗口) | 电影观看 | 支持 | 完整 | 完全 |
| 内联播放器 | AVPlayerViewController(不填满窗口) | 文档内嵌、预览 | 不支持 | 简化 | 部分 |
| 3D 场景实体 | VideoPlayerComponent | 启动画面、视频过渡 | 支持 | 无 | 无 |
| 自定义几何体 | VideoMaterial | 特效、艺术展示 | 支持 | 无 | 无 |
VideoPlayerComponent 使用
(09:56)当需要在 3D 场景中将视频作为实体展示(如启动画面、视频过渡),使用 RealityKit 的 VideoPlayerComponent:
import RealityKit
import AVFoundation
// 创建视频实体
let videoEntity = Entity()
// 创建 AVPlayer
let player = AVPlayer(url: videoURL)
// 附加 VideoPlayerComponent
videoEntity.components[VideoPlayerComponent.self] = VideoPlayerComponent(
avPlayer: player
)
// 像普通实体一样定位
videoEntity.position = [0, 1.5, -2]
videoEntity.scale = [2, 1.125, 1]
// 添加到场景
scene.addChild(videoEntity)
// 播放
player.play()
关键点:
VideoPlayerComponent自动创建正确宽高比的视频网格- 支持显示字幕
- 性能优于 AVPlayerLayer,支持 3D 视频格式
- 适合不需要播放控件和系统集成的场景
VideoMaterial 使用
(10:46)当需要更多控制(如在自定义几何体上显示视频),使用 VideoMaterial:
import RealityKit
import AVFoundation
// 创建自定义几何体
let mesh = MeshResource.generatePlane(width: 2, height: 1.125)
// 创建 VideoMaterial
let player = AVPlayer(url: videoURL)
let videoMaterial = VideoMaterial(avPlayer: player)
// 应用到实体
let videoEntity = ModelEntity(mesh: mesh, materials: [videoMaterial])
scene.addChild(videoEntity)
关键点:
VideoMaterial可在任意几何体上显示视频- 不保证原始宽高比
- 不支持字幕显示
- 适合视频作为特效使用的场景
SwiftUI 集成完整示例
import SwiftUI
import AVKit
import AVFoundation
struct PlayerView: UIViewControllerRepresentable {
let videoURL: URL
func makeUIViewController(context: Context) -> AVPlayerViewController {
let controller = AVPlayerViewController()
let player = AVPlayer()
controller.player = player
// 先设置 player,再加载内容,提升性能
let item = AVPlayerItem(url: videoURL)
player.replaceCurrentItem(with: item)
return controller
}
func updateUIViewController(_ uiViewController: AVPlayerViewController, context: Context) {}
}
struct ContentView: View {
let videoURL = URL(string: "https://example.com/movie.m3u8")!
var body: some View {
PlayerView(videoURL: videoURL)
.ignoresSafeArea()
}
}
关键点:
ignoresSafeArea()确保播放器填满整个窗口- 先设置
controller.player再创建AVPlayerItem,让播放器提前知道显示方式 - 不需要额外配置即可获得空间音频和自动环境调暗
核心启发
-
将现有视频 App 迁移到 visionOS
- 做什么:把现有的 iOS 视频播放 App 用 visionOS SDK 重新编译
- 为什么值得做:零代码改动即可获得空间沉浸播放体验,包括大屏幕、空间音频、环境调暗
- 怎么开始:在 Xcode 中创建 visionOS target,复用现有的 AVPlayerViewController 代码
-
为视频 App 添加 Immersive Space
- 做什么:在播放视频时自动打开 Immersive Space,将用户带入虚拟影院
- 为什么值得做:视频屏幕自动固定在最佳观看位置,控件移近便于交互,提供影院级体验
- 怎么开始:使用
openImmersiveSpaceAPI,在PlayerView的onAppear中触发
-
实现缩略图拖拽预览
- 做什么:为 HLS 流添加 Trick Play track,让用户拖拽进度条时看到画面预览
- 为什么值得做:visionOS 上无法像触屏那样精确拖拽,缩略图帮助用户快速定位
- 怎么开始:在 HLS 打包时添加 I-frame only playlist,宽度 145 像素
-
添加”跳过片头”上下文操作
- 做什么:利用
AVPlayerViewController的 contextual actions API 添加智能跳过按钮 - 为什么值得做:visionOS 上长视频体验更需要便捷导航,上下文操作在需要时自动出现
- 怎么开始:实现
AVPlayerViewControllerDelegate的playerViewController(_:contextualActionsFor:)方法
- 做什么:利用
-
在 3D 场景中使用视频作为环境元素
- 做什么:使用 VideoPlayerComponent 在 RealityKit 场景中添加动态视频元素
- 为什么值得做:为空间体验 App 添加动态背景、信息展示或过渡效果
- 怎么开始:创建 RealityKit 实体,附加 VideoPlayerComponent,定位到场景中
关联 Session
- Deliver video content for spatial experiences — 学习如何为 visionOS 准备和交付 3D 视频流媒体内容
- Design for spatial user interfaces — 空间计算平台的 UI 设计原则
- Meet SwiftUI for spatial computing — 在 visionOS 上使用 SwiftUI 构建界面
评论
GitHub Issues · utterances