Highlight
iOS 16 的系统媒体播放器引入了可自定义的播放速度菜单、更强大的插播广告支持,以及通过 AVPlayerViewController 提供的 metadata 展示优化,让开发者能够在不重新构建播放器 UI 的情况下直接利用系统原生能力提升媒体应用的播放体验。
核心内容
在 iOS 16 之前,如果你想让用户调整视频播放速度、支持插播广告或在播放界面展示更丰富的元数据,几乎注定要重写整个播放器 UI。Apple 在很早之前就提供了 AVPlayerViewController,但它的定制能力一直很有限。开发者面临两个选择:要么接受系统播放器的固定行为,要么自己从零开始构建一个完整播放器。自己构建意味着要处理大量的细节——缓冲指示、播放控制、时间显示、画中画、字幕轨道选择、音频轨道选择、AirPlay 分享,这些功能写起来既耗时又容易出 bug。(00:45)
iOS 16 改变了这个局面。Apple 扩展了 AVPlayerViewController 的 API,让开发者能够直接在系统播放器上挂载自定义功能,而不需要自己维护一套 UI。这包括:你可以向播放速度菜单添加自定义档位(而不是只有 1.0x、1.25x、1.5x、2.0x 这几个固定选项);你可以用 AVPlayerInterstitialEventController 管理插播广告的播放逻辑;你可以通过 externalMetadata 在播放器上展示标题、副标题和描述信息。(01:30)
这些改进的意义在于,它让”使用系统播放器”和”提供定制体验”不再是二选一的关系。你可以继续依赖 Apple 对播放器交互的持续优化(包括对新设备的适配、无障碍支持、与系统功能的集成),同时在关键点上体现自己 App 的特色。这对于媒体类应用尤其重要——用户对播放器有明确的期望,他们习惯了系统的操作方式,但应用提供商又需要展示自己的品牌信息、广告逻辑或特色功能。(02:15)
这场 session 的核心就是展示如何在不过度定制的情况下,用最小的代码量实现这些常见的播放器需求。演讲者不会教你怎么写一个完整的自定义播放器(因为 Apple 更推荐你用系统提供的),而是教你如何扩展系统播放器,让它符合你 App 的需求。(02:45)
详细内容
为播放器设置元数据
(03:30)当你用 AVPlayerViewController 播放一个 URL 时,默认情况下播放器界面只显示时间、播放按钮这些基本控制。它不知道你在播什么。iOS 16 允许你通过 externalMetadata 为 AVPlayerItem 设置元数据,这些信息会自动展示在播放器的信息面板里。
具体做法是创建 AVMutableMetadataItem 数组,每个 item 代表一条元数据。Apple 提供了标准的 identifier 常量来指定字段类型:标题用 .commonIdentifierTitle,副标题用 .iTunesMetadataTrackSubTitle,描述用 .commonIdentifierDescription。代码如下:
let titleItem = AVMutableMetadataItem()
titleItem.identifier = .commonIdentifierTitle
titleItem.value = "WWDC 2022 Session 10147"
let subtitleItem = AVMutableMetadataItem()
subtitleItem.identifier = .iTunesMetadataTrackSubTitle
subtitleItem.value = "Create a great video playback experience"
let infoItem = AVMutableMetadataItem()
infoItem.identifier = .commonIdentifierDescription
infoItem.value = "学习如何利用 iOS 16 的系统媒体播放器构建优秀的媒体应用体验。"
playerItem.externalMetadata = [titleItem, subtitleItem, infoItem]
关键点:
AVMutableMetadataItem的identifier决定了这条元数据的类型,必须使用系统提供的常量value可以是字符串或其他符合元数据规范的类型externalMetadata接受数组,你可以添加更多字段(如 artwork、作者信息等)- 这些信息会自动展示在 AVPlayerViewController 的信息面板中,不需要额外 UI 代码
管理插播广告
(17:00)插播广告(interstitial)是媒体应用的常见需求:前置广告、片尾广告、节目间隙的广告。在 iOS 16 之前,你需要自己管理广告的播放时机、跳过逻辑、与主内容的衔接。现在 AVPlayerInterstitialEventController 提供了声明式的 API 来处理这些场景。
基本思路是创建 AVPlayerInterstitialEventController,把它绑定到主播放器上,然后声明插播事件。每个 AVPlayerInterstitialEvent 对象代表一次插播,包含广告内容(primaryItem)和触发时机(time)。你还可以为事件设置 restrictions,指定广告播放期间的行为约束——比如禁止快进、禁止跳过。
let eventController = AVPlayerInterstitialEventController(primaryPlayer: mediaPlayer)
let event = AVPlayerInterstitialEvent(primaryItem: interstitialItem, time: .zero)
event.restrictions = [
.requiresPlaybackAtPreferredRateForAdvancement,
.constrainsSeekingForwardInPrimaryContent
]
eventController.events.append(event)
关键点:
AVPlayerInterstitialEventController的初始化需要传入主播放器,它会把插播事件和主播放器的生命周期绑在一起AVPlayerInterstitialEvent的primaryItem是广告内容的 AVPlayerItem,time指定在主内容的哪个时间点插入(.zero表示从头开始播广告)restrictions是行为约束数组;requiresPlaybackAtPreferredRateForAdvancement要求用户必须以正常播放速率看完广告才能继续,constrainsSeekingForwardInPrimaryContent禁止在广告播放期间快进主内容- 你可以向
eventController.events添加多个插播事件,比如前置广告 + 节目间隙广告 + 片尾广告
(18:20)插播广告的另一个常见场景是”5 秒后可跳过”。这需要你监听插播事件的展示状态,在 UI 上显示跳过按钮,并在用户点击时调用 cancelCurrentEvent。AVPlayerViewController 会通过 delegate 回调 playerViewController(_:willPresent:) 通知你插播开始展示,你可以在这时启动计时器:
func playerViewController(playerViewController: AVPlayerViewController, willPresent interstitial: AVInterstitialTimeRange) {
showSkipButton(afterTime: 5.0, onPress: {
eventController.cancelCurrentEvent(withResumptionOffset: CMTime.zero)
})
}
关键点:
willPresent回调会在插播开始时触发,参数是插播的时间范围信息- 你需要自己实现
showSkipButton的逻辑,包括 5 秒倒计时和按钮的 UI cancelCurrentEvent(withResumptionOffset:)会立即终止插播,withResumptionOffset指定从主内容的哪个时间点恢复(.zero表示从头开始)- 跳过逻辑需要你自己处理,系统不会自动提供跳过按钮
自定义播放速度
(20:00)系统播放器默认提供 1.0x、1.25x、1.5x、2.0x 四档播放速度。iOS 16 允许你通过 AVPlaybackSpeed 添加自定义档位。这对于长视频类应用很有用——用户可能需要 0.5x 精看,也可能需要 3.0x 快速浏览。
AVPlaybackSpeed 有两个属性:rate 是实际的播放倍速,localizedName 是在 UI 上显示的名称。你可以创建自定义速度对象并追加到 AVPlayerViewController.speeds 数组:
let player = AVPlayerViewController()
player.player = mediaPlayer
present(player, animated: true)
let newSpeed = AVPlaybackSpeed(rate: 2.5, localizedName: "Two and a half times speed")
player.speeds.append(newSpeed)
关键点:
AVPlaybackSpeed的rate是Double类型,1.0 表示正常速度,0.5 表示半速,2.0 表示两倍速localizedName会显示在速度菜单里,你可以用中文、英文或其他语言- 追加到
speeds数组后,新的速度选项会自动出现在播放器速度菜单中 - 你可以追加多个自定义档位,系统会按你在数组中的顺序显示
(22:00)如果你完全不需要播放速度功能(比如你的应用是短视频类,默认就自动播放且用户不需要调速度),可以直接隐藏速度菜单。方法是把 speeds 数组清空:
let player = AVPlayerViewController()
player.player = mediaPlayer
present(player, animated: true)
player.speeds = []
关键点:
- 清空
speeds数组会移除整个速度菜单,播放器界面上不再显示速度控制 - 这比逐个移除档位更直接
- 如果你的媒体类型本身就无需速度调整(比如音乐、某些场景的视频),隐藏可以简化 UI
核心启发
基于 iOS 16 播放器的这些新能力,你可以直接实现以下 feature:
-
为教育类 App 添加”精看模式”和”速览模式” —— 用
AVPlaybackSpeed添加 0.75x、0.5x 等精看档位,以及 2.5x、3.0x 等速览档位,让用户根据学习需求自由切换。入口就在播放器速度菜单,无需额外 UI。实现代码只需要调用player.speeds.append()添加几个档位。 -
为新闻/播客 App 实现”赞助商片段”插播 —— 用
AVPlayerInterstitialEventController在节目间隙自动插入赞助商音频,设置.requiresPlaybackAtPreferredRateForAdvancement强制听完,或者提供”15 秒后跳过”按钮提升体验。你只需要创建插播事件并添加到events数组,系统会自动处理播放时机和状态管理。 -
为媒体库 App 添加丰富的内容信息面板 —— 用
externalMetadata为每个视频设置标题、副标题、描述、封面图等信息,让用户在播放器信息面板里直接看到节目详情,而不需要跳转回列表页。这只需要在播放前为AVPlayerItem设置元数据数组,系统会自动展示。 -
为音乐视频 App 添加”试听片段”插播 —— 在完整 MV 前自动播放 30 秒试听片段,用插播事件管理试听和完整内容的衔接。试听结束后自动进入完整内容,或者提供”立即购买完整版”按钮。这个逻辑可以用一个插播事件加上
willPresent回调实现,无需手动管理播放状态切换。 -
为儿童内容 App 简化播放控制 —— 用
speeds = []隐藏速度菜单,防止儿童误触导致播放混乱;用插播事件的 restrictions 禁止快进,确保内容按顺序播放。这种”防误操作”组合只需要两行代码,就能让系统播放器更适合儿童场景。
关联 Session
- What’s new in AVFoundation — 深入了解 AVFoundation 框架在 iOS 16 中的全面更新,包括本次 session 讨论的播放器扩展。
- Meet AVKit video player standards — 学习如何为你的 App 制定并实施视频播放标准,确保跨平台一致性。
- Design great playback experiences for tvOS — 探索如何将 iOS 的播放器能力扩展到 Apple TV,处理遥控器交互和焦点管理。
- AVFoundation in Photos and Camera — 了解 AVFoundation 与系统相机的集成,为你的媒体 App 添加拍摄和编辑能力。
- What’s new in Camera Capture — 学习 iOS 16 中摄像头捕获的新特性,包括与媒体播放的结合场景。
评论
GitHub Issues · utterances