WWDC Quick Look 💓 By SwiftGGTeam
Create a great spatial playback experience

Create a great spatial playback experience

观看原视频

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,让播放器提前知道显示方式
  • 不需要额外配置即可获得空间音频和自动环境调暗

核心启发

  1. 将现有视频 App 迁移到 visionOS

    • 做什么:把现有的 iOS 视频播放 App 用 visionOS SDK 重新编译
    • 为什么值得做:零代码改动即可获得空间沉浸播放体验,包括大屏幕、空间音频、环境调暗
    • 怎么开始:在 Xcode 中创建 visionOS target,复用现有的 AVPlayerViewController 代码
  2. 为视频 App 添加 Immersive Space

    • 做什么:在播放视频时自动打开 Immersive Space,将用户带入虚拟影院
    • 为什么值得做:视频屏幕自动固定在最佳观看位置,控件移近便于交互,提供影院级体验
    • 怎么开始:使用 openImmersiveSpace API,在 PlayerViewonAppear 中触发
  3. 实现缩略图拖拽预览

    • 做什么:为 HLS 流添加 Trick Play track,让用户拖拽进度条时看到画面预览
    • 为什么值得做:visionOS 上无法像触屏那样精确拖拽,缩略图帮助用户快速定位
    • 怎么开始:在 HLS 打包时添加 I-frame only playlist,宽度 145 像素
  4. 添加”跳过片头”上下文操作

    • 做什么:利用 AVPlayerViewController 的 contextual actions API 添加智能跳过按钮
    • 为什么值得做:visionOS 上长视频体验更需要便捷导航,上下文操作在需要时自动出现
    • 怎么开始:实现 AVPlayerViewControllerDelegateplayerViewController(_:contextualActionsFor:) 方法
  5. 在 3D 场景中使用视频作为环境元素

    • 做什么:使用 VideoPlayerComponent 在 RealityKit 场景中添加动态视频元素
    • 为什么值得做:为空间体验 App 添加动态背景、信息展示或过渡效果
    • 怎么开始:创建 RealityKit 实体,附加 VideoPlayerComponent,定位到场景中

关联 Session

评论

GitHub Issues · utterances