avkit

avkit

熱門

使用 AVKit 打造媒體播放體驗。適用於以下情境:使用 AVPlayerViewController 新增影片播放器、啟用子母畫面 (Picture-in-Picture)、透過 AirPlay 串流媒體、使用 SwiftUI 的 VideoPlayer 視圖、設定播放控制元件、顯示字幕與 CC 字幕 (Closed Captions),或將 AVFoundation 播放功能整合至系統 UI。

961星標
48分支
更新於 2026/7/31
SKILL.md
唯讀
名稱
avkit
描述

使用 AVKit 打造媒體播放體驗。適用於以下情境:使用 AVPlayerViewController 新增影片播放器、啟用子母畫面 (Picture-in-Picture)、透過 AirPlay 串流媒體、使用 SwiftUI 的 VideoPlayer 視圖、設定播放控制元件、顯示字幕與 CC 字幕 (Closed Captions),或將 AVFoundation 播放功能整合至系統 UI。

AVKit

建置於 AVFoundation 之上的高階媒體播放 UI。提供系統標準的影片播放器、子母畫面、AirPlay 串流、播放控制元件以及字幕/CC 字幕顯示。適用於 Swift 6.3 / iOS 26+。

目錄

環境設定

音訊會話設定

當播放類 App 需要支援背景音訊、AirPlay 或子母畫面 (PiP) 時,必須設定對應的音訊會話類別 (Audio Session Category) 與相符的背景模式。

  1. 啟用 Background Modes > Audio, AirPlay, and Picture in Picture(即 UIBackgroundModes 中的 audio 值)
  2. 將音訊會話類別設定為 .playback
  3. 延後呼叫 setActive(true) 直到播放正式開始,避免過早中斷其他 App 的音訊
import AVFoundation

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

func activateAudioSessionWhenPlaybackBegins() {
    do {
        try AVAudioSession.sharedInstance().setActive(true)
    } catch {
        print("Audio session activation failed: \(error)")
    }
}

匯入模組

import AVKit          // AVPlayerViewController, VideoPlayer, PiP
import AVFoundation   // AVPlayer, AVPlayerItem, AVAsset

AVPlayerViewController

AVPlayerViewController 是標準的 UIKit 播放器,開箱即用,直接提供系統播放控制元件、子母畫面 (PiP)、AirPlay、字幕以及畫面分析功能。請勿將其繼承子類化 (Subclass)。

基本呈現方式(全螢幕)

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()
    }
}

內嵌播放 (Inline Playback)

AVPlayerViewController 作為子視圖控制器 (Child View Controller) 加入以實現內嵌播放。
請呼叫 addChild,設定 Constraint 加入視圖,最後呼叫 didMove(toParent:)

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)
}

核心屬性

playerVC.showsPlaybackControls = true                    // 顯示/隱藏系統控制元件
playerVC.videoGravity = .resizeAspect                    // 使用 .resizeAspectFill 進行裁切
playerVC.entersFullScreenWhenPlaybackBegins = false
playerVC.exitsFullScreenWhenPlaybackEnds = true
playerVC.updatesNowPlayingInfoCenter = true              // 自動更新 MPNowPlayingInfoCenter

使用 contentOverlayView 可在影片與播放控制元件之間新增非互動式視圖(例如浮水印、Logo)。

Delegate 委派

實作 AVPlayerViewControllerDelegate 以回應全螢幕轉場、子母畫面 (PiP) 生命週期事件、插播廣告播放以及媒體選擇變更。
可使用轉場協調器 (Transition Coordinator) 的 animate(alongsideTransition:completion:) 來讓自訂 UI 與全螢幕動畫保持同步。

畫面就緒狀態

在顯示播放器之前監聽 isReadyForDisplay,以避免出現黑畫面閃爍:

let observation = playerVC.observe(\.isReadyForDisplay) { observed, _ in
    if observed.isReadyForDisplay {
        // 可安全顯示播放器視圖
    }
}

SwiftUI VideoPlayer

SwiftUI 的 VideoPlayer 視圖封裝了 AVKit 的播放 UI。

基本用法

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 覆蓋層 (Overlay)。該覆蓋層支援互動,但僅會接收系統控制元件未處理的事件。

VideoPlayer(player: player) {
    VStack {
        Spacer()
        HStack {
            Image("logo")
                .resizable()
                .frame(width: 40, height: 40)
                .padding()
            Spacer()
        }
    }
}

透過 UIKit Hosting 取得進階控制權

VideoPlayer 並未公開 AVPlayerViewController 的所有屬性。若需要配置 PiP、處理 Delegate 回呼或控制播放速度,請將 AVPlayerViewController 封裝在 UIViewControllerRepresentable 中。完整模式請參閱 references/avkit-patterns.md

子母畫面

子母畫面 (PiP) 讓使用者能在使用其他 App 時,透過浮動視窗觀看影片。
當 App 完成相關配置、裝置支援 PiP,且目前的 AVPlayerItem 是相容於 AVPlayer 的可播放影片內容時,AVPlayerViewController 會自動支援 PiP。即使 App 與裝置設定正確,僅含音訊的項目、不支援的容器/編解碼器,或是尚未準備好顯示影片的項目,仍可能導致 PiP 無法使用。若為自訂播放器 UI,請直接使用 AVPictureInPictureController

先決條件

  1. 音訊會話類別設定為 .playback(參閱環境設定
  2. 啟用 Background Modes > Audio, AirPlay, and Picture in Picture
  3. 準備好含有可播放影片媒體的 AVPlayerItem(而非僅音訊內容)
  4. 目前播放情境允許 PiP;若為自訂播放器,請監聽 isPictureInPicturePossible

標準播放器 PiP

AVPlayerViewController 預設啟用 PiP。控制自動啟用以及從內嵌切換至 PiP 的轉場行為:

let playerVC = AVPlayerViewController()
playerVC.player = player

// 預設啟用 PiP;設定為 false 以停用
playerVC.allowsPictureInPicturePlayback = true

// 當 App 進入背景時自動啟動 PiP(適用於內嵌/非全螢幕播放器)
playerVC.canStartPictureInPictureAutomaticallyFromInline = true

當 PiP 停止時還原 UI

當使用者點擊 PiP 視窗中的還原按鈕時,請實作 Delegate 方法以重新呈現播放器。呼叫 completion handler 並傳入 true,以通知系統完成還原動畫。

func playerViewController(
    _ playerViewController: AVPlayerViewController,
    restoreUserInterfaceForPictureInPictureStopWithCompletionHandler completionHandler: @escaping (Bool) -> Void
) {
    // 重新呈現或重新內嵌播放器視圖控制器
    present(playerViewController, animated: false) {
        completionHandler(true)
    }
}

自訂播放器 PiP

對於自訂播放器 UI,請搭配 AVPlayerLayer 或 Sample Buffer 內容來源使用 AVPictureInPictureController。建立 PiP UI 之前請先檢查裝置支援度,並在目前的播放情境中啟動 PiP 之前檢查控制器之 isPictureInPicturePossible 屬性。請參閱 references/avkit-patterns.md 以獲取完整的自訂播放器與 Sample Buffer PiP 模式。

guard AVPictureInPictureController.isPictureInPictureSupported() else { return }
let pipController = AVPictureInPictureController(playerLayer: playerLayer)
pipController.delegate = self
pipController.canStartPictureInPictureAutomaticallyFromInline = true

// 請由使用者的 PiP 按鈕動作觸發此方法,絕不要自動呼叫。
if pipController.isPictureInPicturePossible {
    pipController.startPictureInPicture()
}

廣告期間的線性播放

插播廣告時段可來自媒體串流/Manifest(AVFoundation 透過 AVPlayerItem.interstitialTimeRanges 公開),或是來自 App 自行的 AVPlayerInterstitialEventController 排程。在 iOS 上請勿直接指定 interstitialTimeRanges。請僅在必須防止使用者在必要的廣告或法律聲明片段中進行尋軌 (Seek) 時使用 requiresLinearPlayback

// 播放廣告期間
playerVC.requiresLinearPlayback = true

// 廣告播放結束後
playerVC.requiresLinearPlayback = false

AirPlay

當 App 配置、媒體、路線及裝置支援允許外接播放時,AVPlayerViewController 會自動支援 AirPlay。使用標準播放器時不需要額外撰寫程式碼。當有支援 AirPlay 的裝置可用時,系統會在播放控制元件中自動顯示 AirPlay 按鈕。

AVRoutePickerView

在播放器 UI 外新增獨立的 AirPlay 裝置選擇器按鈕:

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  // 優先顯示支援影片傳送的裝置
    containerView.addSubview(routePicker)
}

外接播放

AVPlayer 預設允許外接播放。請為 AirPlay 保持啟用狀態,或在其他地方的程式碼可能停用它時進行明確設定:

player.allowsExternalPlayback = true

僅在希望播放器在外接螢幕模式啟用時自動切換至外接播放時,才設定 usesExternalPlaybackWhileExternalScreenIsActive

播放控制元件與播放速度

自訂播放速度

在播放器 UI 中提供使用者可選擇的播放速度選項:

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 可還原預設的播放速度選項。

快轉/倒帶與尋軌

在 iOS 上,自訂 App 控制元件請使用標準播放控制介面與 AVPlayer.seek(...)AVPlayerViewController 的快轉/倒帶行為 API(例如 isSkipForwardEnabledisSkipBackwardEnabledskippingBehavior)主要針對 tvOS 設計;請勿在 iOS 播放器實作中使用這些 API。

即時播放資訊整合

AVPlayerViewController 預設會自動更新 MPNowPlayingInfoCenter。如果您需要手動管理即時播放資訊 (Now Playing Info),請停用此功能:

playerVC.updatesNowPlayingInfoCenter = false

字幕與 CC 字幕

當媒體包含適當的文字軌時,AVKit 會自動處理字幕與 CC 字幕 (Closed Caption) 的顯示。使用者可在「設定」>「輔助使用」>「字幕與隱藏字幕」中控制字幕偏好設定。

程式化選擇字幕

let asset = player.currentItem?.asset

if let group = try await asset?.loadMediaSelectionGroup(for: .legible),
   let english = group.options.first(where: { option in
       option.locale?.language.languageCode?.identifier == "en"
   }) {
    player.currentItem?.se