avkit

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

AVKit

AVKit

High-level media playback UI built on AVFoundation. Provides system-standard video players, Picture-in-Picture, AirPlay routing, transport controls, and subtitle/caption display. Targets Swift 6.3 / iOS 26+.
基于AVFoundation构建的高级媒体播放UI。提供系统标准的视频播放器、画中画(Picture-in-Picture)、AirPlay媒体路由、播放控制以及字幕/隐藏式字幕显示功能。适配Swift 6.3 / iOS 26+。

Contents

配置步骤

音频会话配置

在进行任何播放操作前,先配置音频会话和后台模式。如果跳过这一步,画中画和后台音频会静默失效。
  1. 在Info.plist的
    UIBackgroundModes
    中添加
    audio
    后台模式
  2. 将音频会话类别设置为
    .playback
swift
import AVFoundation

func configureAudioSession() {
    let session = AVAudioSession.sharedInstance()
    do {
        try session.setCategory(.playback, mode: .moviePlayback)
        try session.setActive(true)
    } catch {
        print("Audio session configuration failed: \(error)")
    }
}

Setup

导入依赖

Audio Session Configuration

Configure the audio session and background modes before any playback. Without this, PiP and background audio fail silently.
  1. Add the
    audio
    background mode to
    UIBackgroundModes
    in Info.plist
  2. Set the audio session category to
    .playback
swift
import AVFoundation

func configureAudioSession() {
    let session = AVAudioSession.sharedInstance()
    do {
        try session.setCategory(.playback, mode: .moviePlayback)
        try session.setActive(true)
    } catch {
        print("Audio session configuration failed: \(error)")
    }
}
swift
import AVKit          // AVPlayerViewController, VideoPlayer, PiP
import AVFoundation   // AVPlayer, AVPlayerItem, AVAsset

Imports

AVPlayerViewController

swift
import AVKit          // AVPlayerViewController, VideoPlayer, PiP
import AVFoundation   // AVPlayer, AVPlayerItem, AVAsset
AVPlayerViewController
是标准的UIKit播放器。它默认提供系统播放控制、画中画(PiP)、AirPlay、字幕以及帧分析功能。请勿对其进行子类化。

AVPlayerViewController

基础全屏展示

AVPlayerViewController
is the standard UIKit player. It provides system playback controls, PiP, AirPlay, subtitles, and frame analysis out of the box. Do not subclass it.
swift
import AVKit

func presentPlayer(from viewController: UIViewController, url: URL) {
    let player = AVPlayer(url: url)
    let playerVC = AVPlayerViewController()
    playerVC.player = player

    viewController.present(playerVC, animated: true) {
        player.play()
    }
}

Basic Presentation (Full Screen)

内嵌式播放

swift
import AVKit

func presentPlayer(from viewController: UIViewController, url: URL) {
    let player = AVPlayer(url: url)
    let playerVC = AVPlayerViewController()
    playerVC.player = player

    viewController.present(playerVC, animated: true) {
        player.play()
    }
}
AVPlayerViewController
作为子视图控制器添加以实现内嵌播放。调用
addChild
,添加视图并设置约束,然后调用
didMove(toParent:)
swift
func embedPlayer(in parent: UIViewController, container: UIView, url: URL) {
    let playerVC = AVPlayerViewController()
    playerVC.player = AVPlayer(url: url)

    parent.addChild(playerVC)
    container.addSubview(playerVC.view)
    playerVC.view.translatesAutoresizingMaskIntoConstraints = false
    NSLayoutConstraint.activate([
        playerVC.view.leadingAnchor.constraint(equalTo: container.leadingAnchor),
        playerVC.view.trailingAnchor.constraint(equalTo: container.trailingAnchor),
        playerVC.view.topAnchor.constraint(equalTo: container.topAnchor),
        playerVC.view.bottomAnchor.constraint(equalTo: container.bottomAnchor)
    ])
    playerVC.didMove(toParent: parent)
}

Inline (Embedded) Playback

关键属性

Add
AVPlayerViewController
as a child view controller for inline playback. Call
addChild
, add the view with constraints, then call
didMove(toParent:)
.
swift
func embedPlayer(in parent: UIViewController, container: UIView, url: URL) {
    let playerVC = AVPlayerViewController()
    playerVC.player = AVPlayer(url: url)

    parent.addChild(playerVC)
    container.addSubview(playerVC.view)
    playerVC.view.translatesAutoresizingMaskIntoConstraints = false
    NSLayoutConstraint.activate([
        playerVC.view.leadingAnchor.constraint(equalTo: container.leadingAnchor),
        playerVC.view.trailingAnchor.constraint(equalTo: container.trailingAnchor),
        playerVC.view.topAnchor.constraint(equalTo: container.topAnchor),
        playerVC.view.bottomAnchor.constraint(equalTo: container.bottomAnchor)
    ])
    playerVC.didMove(toParent: parent)
}
swift
playerVC.showsPlaybackControls = true                    // Show/hide system controls
playerVC.videoGravity = .resizeAspect                    // .resizeAspectFill to crop
playerVC.entersFullScreenWhenPlaybackBegins = false
playerVC.exitsFullScreenWhenPlaybackEnds = true
playerVC.updatesNowPlayingInfoCenter = true              // Auto-updates MPNowPlayingInfoCenter
使用
contentOverlayView
在视频和播放控制栏之间添加非交互视图(如水印、logo)。

Key Properties

代理

swift
playerVC.showsPlaybackControls = true                    // Show/hide system controls
playerVC.videoGravity = .resizeAspect                    // .resizeAspectFill to crop
playerVC.entersFullScreenWhenPlaybackBegins = false
playerVC.exitsFullScreenWhenPlaybackEnds = true
playerVC.updatesNowPlayingInfoCenter = true              // Auto-updates MPNowPlayingInfoCenter
Use
contentOverlayView
to add non-interactive views (watermarks, logos) between the video and transport controls.
遵循
AVPlayerViewControllerDelegate
协议以响应全屏切换、画中画生命周期事件、插播内容播放以及媒体选择变更。使用过渡协调器的
animate(alongsideTransition:completion:)
方法将你的UI与全屏动画同步。

Delegate

显示就绪状态

Adopt
AVPlayerViewControllerDelegate
to respond to full-screen transitions, PiP lifecycle events, interstitial playback, and media selection changes. Use the transition coordinator's
animate(alongsideTransition:completion:)
to synchronize your UI with full-screen animations.
在展示播放器前监听
isReadyForDisplay
属性,避免出现黑屏闪烁:
swift
let observation = playerVC.observe(\.isReadyForDisplay) { observed, _ in
    if observed.isReadyForDisplay {
        // Safe to show the player view
    }
}

Display Readiness

SwiftUI VideoPlayer

Observe
isReadyForDisplay
before showing the player to avoid a black flash:
swift
let observation = playerVC.observe(\.isReadyForDisplay) { observed, _ in
    if observed.isReadyForDisplay {
        // Safe to show the player view
    }
}
VideoPlayer
SwiftUI视图封装了AVKit的播放UI。

SwiftUI VideoPlayer

基础用法

The
VideoPlayer
SwiftUI view wraps AVKit's playback UI.
swift
import SwiftUI
import AVKit

struct PlayerView: View {
    @State private var player: AVPlayer?

    var body: some View {
        Group {
            if let player {
                VideoPlayer(player: player)
                    .frame(height: 300)
            } else {
                ProgressView()
            }
        }
        .task {
            let url = URL(string: "https://example.com/video.m3u8")!
            player = AVPlayer(url: url)
        }
    }
}

Basic Usage

视频叠加层

swift
import SwiftUI
import AVKit

struct PlayerView: View {
    @State private var player: AVPlayer?

    var body: some View {
        Group {
            if let player {
                VideoPlayer(player: player)
                    .frame(height: 300)
            } else {
                ProgressView()
            }
        }
        .task {
            let url = URL(string: "https://example.com/video.m3u8")!
            player = AVPlayer(url: url)
        }
    }
}
在视频内容上方添加非交互式SwiftUI叠加层。
swift
VideoPlayer(player: player) {
    VStack {
        Spacer()
        HStack {
            Image("logo")
                .resizable()
                .frame(width: 40, height: 40)
                .padding()
            Spacer()
        }
    }
}

Video Overlay

借助UIKit实现高级控制

Add a non-interactive SwiftUI overlay on top of video content.
swift
VideoPlayer(player: player) {
    VStack {
        Spacer()
        HStack {
            Image("logo")
                .resizable()
                .frame(width: 40, height: 40)
                .padding()
            Spacer()
        }
    }
}
VideoPlayer
并未暴露
AVPlayerViewController
的所有属性。如需配置画中画、代理回调或播放速度控制,请将
AVPlayerViewController
封装在
UIViewControllerRepresentable
中。完整实现模式请参考references/avkit-patterns.md

UIKit Hosting for Advanced Control

画中画(Picture-in-Picture)

VideoPlayer
does not expose all
AVPlayerViewController
properties. For PiP configuration, delegate callbacks, or playback speed control, wrap
AVPlayerViewController
in a
UIViewControllerRepresentable
. See the full pattern in references/avkit-patterns.md.
画中画功能允许用户在使用其他应用时,以浮动窗口形式观看视频。一旦配置好音频会话,
AVPlayerViewController
会自动支持画中画。对于自定义播放器UI,请直接使用
AVPictureInPictureController

Picture-in-Picture

前提条件

PiP lets users watch video in a floating window while using other apps.
AVPlayerViewController
supports PiP automatically once the audio session is configured. For custom player UIs, use
AVPictureInPictureController
directly.
  1. 音频会话类别设置为
    .playback
    (参见配置步骤
  2. UIBackgroundModes
    中添加
    audio
    后台模式

Prerequisites

标准播放器画中画

  1. Audio session category set to
    .playback
    (see Setup)
  2. audio
    background mode in
    UIBackgroundModes
AVPlayerViewController
默认启用画中画。可以控制自动激活以及内嵌到画中画的切换:
swift
let playerVC = AVPlayerViewController()
playerVC.player = player

// 画中画默认启用;设置为false可禁用
playerVC.allowsPictureInPicturePlayback = true

// 当应用进入后台时自动启动画中画(适用于内嵌/非全屏播放器)
playerVC.canStartPictureInPictureAutomaticallyFromInline = true

Standard Player PiP

画中画停止时恢复UI

PiP is enabled by default on
AVPlayerViewController
. Control automatic activation and inline-to-PiP transitions:
swift
let playerVC = AVPlayerViewController()
playerVC.player = player

// PiP enabled by default; set false to disable
playerVC.allowsPictureInPicturePlayback = true

// Auto-start PiP when app backgrounds (for inline/non-fullscreen players)
playerVC.canStartPictureInPictureAutomaticallyFromInline = true
当用户点击画中画窗口的恢复按钮时,实现代理方法以重新展示你的播放器。调用完成处理程序并传入
true
,通知系统完成恢复动画。
swift
func playerViewController(
    _ playerViewController: AVPlayerViewController,
    restoreUserInterfaceForPictureInPictureStopWithCompletionHandler completionHandler: @escaping (Bool) -> Void
) {
    // Re-present or re-embed the player view controller
    present(playerViewController, animated: false) {
        completionHandler(true)
    }
}

Restoring the UI When PiP Stops

自定义播放器画中画

When the user taps the restore button in PiP, implement the delegate method to re-present your player. Call the completion handler with
true
to signal the system to finish the restore animation.
swift
func playerViewController(
    _ playerViewController: AVPlayerViewController,
    restoreUserInterfaceForPictureInPictureStopWithCompletionHandler completionHandler: @escaping (Bool) -> Void
) {
    // Re-present or re-embed the player view controller
    present(playerViewController, animated: false) {
        completionHandler(true)
    }
}
对于自定义播放器UI,请结合
AVPlayerLayer
或样本缓冲区内容源使用
AVPictureInPictureController
。首先检查
isPictureInPictureSupported()
是否支持。完整的自定义播放器和样本缓冲区画中画模式请参考references/avkit-patterns.md
swift
guard AVPictureInPictureController.isPictureInPictureSupported() else { return }
let pipController = AVPictureInPictureController(playerLayer: playerLayer)
pipController.delegate = self
pipController.canStartPictureInPictureAutomaticallyFromInline = true

Custom Player PiP

广告期间的线性播放

For custom player UIs, use
AVPictureInPictureController
with an
AVPlayerLayer
or sample buffer content source. Check
isPictureInPictureSupported()
first. See references/avkit-patterns.md for full custom player and sample buffer PiP patterns.
swift
guard AVPictureInPictureController.isPictureInPictureSupported() else { return }
let pipController = AVPictureInPictureController(playerLayer: playerLayer)
pipController.delegate = self
pipController.canStartPictureInPictureAutomaticallyFromInline = true
通过切换
requiresLinearPlayback
属性,防止在广告或法律声明播放期间进行快进/后退操作:
swift
// 广告播放期间
playerVC.requiresLinearPlayback = true

// 广告播放完成后
playerVC.requiresLinearPlayback = false

Linear Playback During Ads

AirPlay

Prevent seeking during ads or legal notices by toggling
requiresLinearPlayback
:
swift
// During an ad
playerVC.requiresLinearPlayback = true

// After the ad completes
playerVC.requiresLinearPlayback = false
AVPlayerViewController
自动支持AirPlay。使用标准播放器时无需额外代码。当存在支持AirPlay的设备时,系统会在播放控制栏中显示AirPlay按钮。

AirPlay

AVRoutePickerView

AVPlayerViewController
supports AirPlay automatically. No additional code is required when using the standard player. The system displays the AirPlay button in the transport controls when AirPlay-capable devices are available.
在播放器UI外添加独立的AirPlay路由选择按钮:
swift
import AVKit

func addRoutePicker(to containerView: UIView) {
    let routePicker = AVRoutePickerView(frame: CGRect(x: 0, y: 0, width: 44, height: 44))
    routePicker.activeTintColor = .systemBlue
    routePicker.prioritizesVideoDevices = true  // Show video-capable routes first
    containerView.addSubview(routePicker)
}

AVRoutePickerView

启用外部播放

Add a standalone AirPlay route picker button outside the player UI:
swift
import AVKit

func addRoutePicker(to containerView: UIView) {
    let routePicker = AVRoutePickerView(frame: CGRect(x: 0, y: 0, width: 44, height: 44))
    routePicker.activeTintColor = .systemBlue
    routePicker.prioritizesVideoDevices = true  // Show video-capable routes first
    containerView.addSubview(routePicker)
}
确保
AVPlayer
允许外部播放(默认已启用):
swift
player.allowsExternalPlayback = true
player.usesExternalPlaybackWhileExternalScreenIsActive = true

Enabling External Playback

播放控制与播放速度

自定义播放速度

Ensure
AVPlayer
allows external playback (enabled by default):
swift
player.allowsExternalPlayback = true
player.usesExternalPlaybackWhileExternalScreenIsActive = true
在播放器UI中提供用户可选的播放速度:
swift
let playerVC = AVPlayerViewController()
playerVC.speeds = [
    AVPlaybackSpeed(rate: 0.5, localizedName: "Half Speed"),
    AVPlaybackSpeed(rate: 1.0, localizedName: "Normal"),
    AVPlaybackSpeed(rate: 1.5, localizedName: "1.5x"),
    AVPlaybackSpeed(rate: 2.0, localizedName: "Double Speed")
]
使用
AVPlaybackSpeed.systemDefaultSpeeds
恢复默认速度选项。

Transport Controls and Playback Speed

跳过功能

Custom Playback Speeds

Provide user-selectable playback speeds in the player UI:
swift
let playerVC = AVPlayerViewController()
playerVC.speeds = [
    AVPlaybackSpeed(rate: 0.5, localizedName: "Half Speed"),
    AVPlaybackSpeed(rate: 1.0, localizedName: "Normal"),
    AVPlaybackSpeed(rate: 1.5, localizedName: "1.5x"),
    AVPlaybackSpeed(rate: 2.0, localizedName: "Double Speed")
]
Use
AVPlaybackSpeed.systemDefaultSpeeds
to restore the default speed options.
配置快进/后退跳过控制:
swift
playerVC.isSkipForwardEnabled = true
playerVC.isSkipBackwardEnabled = true

Skipping Behavior

现在播放信息集成

Configure forward/backward skip controls:
swift
playerVC.isSkipForwardEnabled = true
playerVC.isSkipBackwardEnabled = true
AVPlayerViewController
默认会自动更新
MPNowPlayingInfoCenter
。如果你手动管理现在播放信息,请禁用此功能:
swift
playerVC.updatesNowPlayingInfoCenter = false

Now Playing Integration

字幕与隐藏式字幕

AVPlayerViewController
updates
MPNowPlayingInfoCenter
automatically by default. Disable this if you manage Now Playing info manually:
swift
playerVC.updatesNowPlayingInfoCenter = false
当媒体包含合适的文本轨道时,AVKit会自动处理字幕和隐藏式字幕的显示。用户可在“设置 > 辅助功能 > 字幕与隐藏式字幕”中控制字幕偏好。

Subtitles and Closed Captions

限制字幕语言

AVKit handles subtitle and closed caption display automatically when the media contains appropriate text tracks. Users control subtitle preferences in Settings > Accessibility > Subtitles & Captioning.
swift
// 仅显示英文和西班牙文字幕选项
playerVC.allowedSubtitleOptionLanguages = ["en", "es"]

Restricting Subtitle Languages

强制显示字幕

swift
// Only show English and Spanish subtitle options
playerVC.allowedSubtitleOptionLanguages = ["en", "es"]
强制始终显示字幕(用户无法关闭):
swift
playerVC.requiresFullSubtitles = true

Requiring Subtitles

媒体选择(代理)

Force subtitles to always display (the user cannot turn them off):
swift
playerVC.requiresFullSubtitles = true
响应用户切换字幕或音轨的操作:
swift
func playerViewController(
    _ playerViewController: AVPlayerViewController,
    didSelect mediaSelectionOption: AVMediaSelectionOption?,
    in mediaSelectionGroup: AVMediaSelectionGroup
) {
    if let option = mediaSelectionOption {
        print("Selected: \(option.displayName)")
    }
}

Media Selection (Delegate)

在HLS中提供字幕轨道

Respond to the user changing subtitle or audio track selection:
swift
func playerViewController(
    _ playerViewController: AVPlayerViewController,
    didSelect mediaSelectionOption: AVMediaSelectionOption?,
    in mediaSelectionGroup: AVMediaSelectionGroup
) {
    if let option = mediaSelectionOption {
        print("Selected: \(option.displayName)")
    }
}
字幕和隐藏式字幕嵌入在HLS清单中。AVKit会从
AVAsset
AVMediaSelectionGroup
中读取这些轨道。对于本地文件,请使用
AVMutableComposition
添加
AVMediaCharacteristic.legible
轨道。

Providing Subtitle Tracks in HLS

常见错误

不要:子类化AVPlayerViewController

Subtitles and closed captions are embedded in HLS manifests. AVKit reads them from
AVMediaSelectionGroup
on the
AVAsset
. For local files, use
AVMutableComposition
to add
AVMediaCharacteristic.legible
tracks.
Apple明确声明此操作不受支持。可能会导致未定义行为,或在未来OS版本中崩溃。
swift
// 错误示例
class MyPlayerVC: AVPlayerViewController { } // 不被支持

// 正确做法:使用组合模式+代理
let playerVC = AVPlayerViewController()
playerVC.delegate = coordinator

Common Mistakes

不要:跳过画中画的音频会话配置

DON'T: Subclass AVPlayerViewController

Apple explicitly states this is unsupported. It may cause undefined behavior or crash on future OS versions.
swift
// WRONG
class MyPlayerVC: AVPlayerViewController { } // Unsupported

// CORRECT: Use composition with delegation
let playerVC = AVPlayerViewController()
playerVC.delegate = coordinator
如果音频会话未设置为
.playback
,画中画会静默失效。后台音频也会停止工作。
swift
// 错误示例:使用默认音频会话
let playerVC = AVPlayerViewController()
playerVC.player = player // 画中画无法工作

// 正确做法:先配置音频会话
try AVAudioSession.sharedInstance().setCategory(.playback, mode: .moviePlayback)
try AVAudioSession.sharedInstance().setActive(true)
let playerVC = AVPlayerViewController()
playerVC.player = player

DON'T: Skip audio session configuration for PiP

不要:忘记实现画中画恢复代理或其完成处理程序

PiP fails silently if the audio session is not set to
.playback
. Background audio also stops working.
swift
// WRONG: Default audio session
let playerVC = AVPlayerViewController()
playerVC.player = player // PiP won't work

// CORRECT: Configure audio session first
try AVAudioSession.sharedInstance().setCategory(.playback, mode: .moviePlayback)
try AVAudioSession.sharedInstance().setActive(true)
let playerVC = AVPlayerViewController()
playerVC.player = player
如果没有实现
restoreUserInterfaceForPictureInPictureStopWithCompletionHandler
,系统无法将用户带回你的播放器。如果不调用
completionHandler(true)
,会导致系统状态不一致。
swift
// 错误示例:没有实现代理方法或未调用完成处理程序
// 用户点击画中画的恢复按钮 -> 无反应或动画卡住

// 正确做法
func playerViewController(
    _ playerViewController: AVPlayerViewController,
    restoreUserInterfaceForPictureInPictureStopWithCompletionHandler completionHandler: @escaping (Bool) -> Void
) {
    present(playerViewController, animated: false) {
        completionHandler(true)
    }
}

DON'T: Forget the PiP restore delegate or its completion handler

不要:在SwiftUI视图的init中创建AVPlayer

Without
restoreUserInterfaceForPictureInPictureStopWithCompletionHandler
, the system cannot return the user to your player. Failing to call
completionHandler(true)
leaves the system in an inconsistent state.
swift
// WRONG: No delegate method or missing completionHandler call
// User taps restore in PiP -> nothing happens or animation hangs

// CORRECT
func playerViewController(
    _ playerViewController: AVPlayerViewController,
    restoreUserInterfaceForPictureInPictureStopWithCompletionHandler completionHandler: @escaping (Bool) -> Void
) {
    present(playerViewController, animated: false) {
        completionHandler(true)
    }
}
提前创建播放器会导致性能问题。SwiftUI可能会多次重建视图。
swift
// 错误示例:每次视图初始化时创建
struct PlayerView: View {
    let player = AVPlayer(url: videoURL) // 每次视图评估时都会重建

    var body: some View { VideoPlayer(player: player) }
}

// 正确做法:使用@State并延迟创建
struct PlayerView: View {
    @State private var player: AVPlayer?

    var body: some View {
        VideoPlayer(player: player)
            .task { player = AVPlayer(url: videoURL) }
    }
}

DON'T: Create AVPlayer in a SwiftUI view's init

审核清单

Creating the player eagerly causes performance issues. SwiftUI may recreate the view multiple times.
swift
// WRONG: Created on every view init
struct PlayerView: View {
    let player = AVPlayer(url: videoURL) // Re-created on every view evaluation

    var body: some View { VideoPlayer(player: player) }
}

// CORRECT: Use @State and defer creation
struct PlayerView: View {
    @State private var player: AVPlayer?

    var body: some View {
        VideoPlayer(player: player)
            .task { player = AVPlayer(url: videoURL) }
    }
}
  • 音频会话类别已设置为
    .playback
    并使用
    mode: .moviePlayback
  • UIBackgroundModes
    中已添加
    audio
    后台模式
  • 未对
    AVPlayerViewController
    进行子类化
  • 已实现画中画恢复代理方法并调用了
    completionHandler(true)
  • 在SwiftUI中使用
    .task
    延迟创建
    AVPlayer
    (而非提前创建)
  • 对内嵌播放器设置了
    canStartPictureInPictureAutomaticallyFromInline
  • 仅在必要的广告/法律片段期间切换
    requiresLinearPlayback
  • AVPlayer
    已启用
    allowsExternalPlayback
    以支持AirPlay
  • 已使用实际媒体轨道测试字幕语言限制
  • 已正确设置视频缩放模式(
    .resizeAspect
    .resizeAspectFill
  • 在展示播放器视图前监听了
    isReadyForDisplay
  • 已处理网络流内容的错误(HLS加载失败、超时等)

Review Checklist

参考资料

  • Audio session category set to
    .playback
    with
    mode: .moviePlayback
  • audio
    background mode added to
    UIBackgroundModes
    in Info.plist
  • AVPlayerViewController
    is not subclassed
  • PiP restore delegate method implemented and calls
    completionHandler(true)
  • AVPlayer
    deferred to
    .task
    in SwiftUI (not created eagerly)
  • canStartPictureInPictureAutomaticallyFromInline
    set for inline players
  • requiresLinearPlayback
    toggled only during required ad/legal segments
  • allowsExternalPlayback
    enabled on
    AVPlayer
    for AirPlay support
  • Subtitle language restrictions tested with actual media tracks
  • Video gravity set appropriately (
    .resizeAspect
    vs
    .resizeAspectFill
    )
  • isReadyForDisplay
    observed before showing the player view
  • Error handling for network-streamed content (HLS failures, timeouts)

References