AVKit
AVFoundation上に構築された高レベルなメディア再生UI。システム標準の動画プレーヤー、ピクチャーインピクチャー(PiP)、AirPlayルーティング、トランスポートコントロール、字幕・キャプション表示を提供します。Swift 6.3 / iOS 26+を対象としています。
目次
- セットアップ
- AVPlayerViewController
- SwiftUI VideoPlayer
- ピクチャーインピクチャー
- AirPlay
- トランスポートコントロールと再生速度
- 字幕とクローズドキャプション
- よくある間違い
- レビューチェックリスト
- 参考資料
セットアップ
オーディオセッション設定
再生を開始する前に、オーディオセッションとバックグラウンドモードを設定します。これがないと、PiPやバックグラウンドオーディオは静かに失敗します。
- Info.plistの
UIBackgroundModesにaudioバックグラウンドモードを追加する - オーディオセッションカテゴリを
.playbackに設定する
import AVFoundation
func configureAudioSession() {
let session = AVAudioSession.sharedInstance()
do {
try session.setCategory(.playback, mode: .moviePlayback)
try session.setActive(true)
} catch {
print("オーディオセッションの設定に失敗しました: \(error)")
}
}
インポート
import AVKit // AVPlayerViewController, VideoPlayer, PiP
import AVFoundation // AVPlayer, AVPlayerItem, AVAsset
AVPlayerViewController
AVPlayerViewControllerは標準のUIKitプレーヤーです。システムの再生コントロール、PiP、AirPlay、字幕、フレーム分析をそのまま提供します。サブクラス化しないでください。
基本表示(全画面)
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:)を呼び出します。
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を使用して、ビデオとトランスポートコントロールの間に非インタラクティブなビュー(透かし、ロゴ)を追加します。
デリゲート
AVPlayerViewControllerDelegateに準拠して、全画面遷移、PiPライフサイクルイベント、インタースティシャル再生、メディア選択の変更に応答します。トランジションコーディネーターの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オーバーレイを追加します。
VideoPlayer(player: player) {
VStack {
Spacer()
HStack {
Image("logo")
.resizable()
.frame(width: 40, height: 40)
.padding()
Spacer()
}
}
}
高度な制御のためのUIKitホスティング
VideoPlayerはすべてのAVPlayerViewControllerプロパティを公開しません。PiP設定、デリゲートコールバック、再生速度制御には、AVPlayerViewControllerをUIViewControllerRepresentableでラップします。完全なパターンはreferences/avkit-patterns.mdを参照してください。
ピクチャーインピクチャー
PiPを使用すると、ユーザーは他のアプリを使用しながら、フローティングウィンドウでビデオを視聴できます。AVPlayerViewControllerは、オーディオセッションが設定されていれば、PiPを自動的にサポートします。カスタムプレーヤーUIの場合は、AVPictureInPictureControllerを直接使用します。
前提条件
- オーディオセッションカテゴリが
.playbackに設定されていること(セットアップ参照) UIBackgroundModesにaudioバックグラウンドモードがあること
標準プレーヤーPiP
PiPはAVPlayerViewControllerでデフォルトで有効です。自動起動とインラインからPiPへの遷移を制御します。
let playerVC = AVPlayerViewController()
playerVC.player = player
// PiPはデフォルトで有効。無効にするにはfalseを設定
playerVC.allowsPictureInPicturePlayback = true
// アプリがバックグラウンドになったときにPiPを自動起動(インライン/非全画面プレーヤー用)
playerVC.canStartPictureInPictureAutomaticallyFromInline = true
PiP停止時のUIの復元
ユーザーがPiPで復元ボタンをタップしたときに、デリゲートメソッドを実装してプレーヤーを再表示します。完了ハンドラーをtrueで呼び出して、システムに復元アニメーションの完了を通知します。
func playerViewController(
_ playerViewController: AVPlayerViewController,
restoreUserInterfaceForPictureInPictureStopWithCompletionHandler completionHandler: @escaping (Bool) -> Void
) {
// プレーヤービューコントローラーを再表示または再埋め込み
present(playerViewController, animated: false) {
completionHandler(true)
}
}
カスタムプレーヤーPiP
カスタムプレーヤーUIの場合は、AVPlayerLayerまたはサンプルバッファコンテンツソースとともにAVPictureInPictureControllerを使用します。最初にisPictureInPictureSupported()を確認します。完全なカスタムプレーヤーとサンプルバッファPiPパターンについては、references/avkit-patterns.mdを参照してください。
guard AVPictureInPictureController.isPictureInPictureSupported() else { return }
let pipController = AVPictureInPictureController(playerLayer: playerLayer)
pipController.delegate = self
pipController.canStartPictureInPictureAutomaticallyFromInline = true
広告中の線形再生
広告や法的通知中にシークを防ぐには、requiresLinearPlaybackを切り替えます。
// 広告中
playerVC.requiresLinearPlayback = true
// 広告終了後
playerVC.requiresLinearPlayback = false
AirPlay
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が外部再生を許可していることを確認します(デフォルトで有効)。
player.allowsExternalPlayback = true
player.usesExternalPlaybackWhileExternalScreenIsActive = true
トランスポートコントロールと再生速度
カスタム再生速度
プレーヤーUIでユーザーが選択可能な再生速度を提供します。
let playerVC = AVPlayerViewController()
playerVC.speeds = [
AVPlaybackSpeed(rate: 0.5, localizedName: "半分の速度"),
AVPlaybackSpeed(rate: 1.0, localizedName: "通常"),
AVPlaybackSpeed(rate: 1.5, localizedName: "1.5倍"),
AVPlaybackSpeed(rate: 2.0, localizedName: "2倍")
]
AVPlaybackSpeed.systemDefaultSpeedsを使用して、デフォルトの速度オプションに戻します。
スキップ動作
前方/後方スキップコントロールを設定します。
playerVC.isSkipForwardEnabled = true
playerVC.isSkipBackwardEnabled = true
再生中情報の統合
AVPlayerViewControllerは、デフォルトでMPNowPlayingInfoCenterを自動的に更新します。再生中情報を手動で管理する場合は、これを無効にします。
playerVC.updatesNowPlayingInfoCenter = false
字幕とクローズドキャプション
AVKitは、メディアに適切なテキストトラックが含まれている場合、字幕とクローズドキャプションの表示を自動的に処理します。ユーザーは設定 > アクセシビリティ > 字幕とキャプションで字幕の設定を制御できます。
字幕言語の制限
// 英語とスペイン語の字幕オプションのみ表示
playerVC.allowedSubtitleOptionLanguages = ["en", "es"]
字幕の強制
字幕を常に表示するように強制します(ユーザーはオフにできません)。
playerVC.requiresFullSubtitles = true
メディア選択(デリゲート)
ユーザーが字幕または音声トラックの選択を変更したときに応答します。
func playerViewController(
_ playerViewController: AVPlayerViewController,
didSelect mediaSelectionOption: AVMediaSelectionOption?,
in mediaSelectionGroup: AVMediaSelectionGroup
) {
if let option = mediaSelectionOption {
print("選択されました: \(option.displayName)")
}
}
HLSでの字幕トラックの提供
字幕とクローズドキャプションはHLSマニフェストに埋め込まれています。AVKitはAVAsset上のAVMediaSelectionGroupからそれらを読み取ります。ローカルファイルの場合は、AVMutableCompositionを使用してAVMediaCharacteristic.legibleトラックを追加します。
よくある間違い
してはいけないこと: AVPlayerViewControllerのサブクラス化
Appleは明示的にこれをサポートしないと述べています。将来のOSバージョンで未定義の動作やクラッシュを引き起こす可能性があります。
// 間違い
class MyPlayerVC: AVPlayerViewController { } // サポート対象外
// 正しい: 委譲による構成を使用
let playerVC = AVPlayerViewController()
playerVC.delegate = coordinator
してはいけないこと: PiPのためにオーディオセッション設定をスキップする
オーディオセッションが.playbackに設定されていない場合、PiPは静かに失敗します。バックグラウンドオーディオも機能しなくなります。
// 間違い: デフォルトのオーディオセッション
let playerVC = AVPlayerViewController()
playerVC.player = player // PiPは動作しない
// 正しい: 最初にオーディオセッションを設定
try AVAudioSession.sharedInstance().setCategory(.playback, mode: .moviePlayback)
try AVAudioSession.sharedInstance().setActive(true)
let playerVC = AVPlayerViewController()
playerVC.player = player
してはいけないこと: PiP復元デリゲートまたはその完了ハンドラーを忘れる
restoreUserInterfaceForPictureInPictureStopWithCompletionHandlerがないと、システムはユーザーをプレーヤーに戻せません。completionHandler(true)を呼び出さないと、システムが不整合な状態になります。
// 間違い: デリゲートメソッドがない、またはcompletionHandlerの呼び出しがない
// ユーザーがPiPで復元をタップ -> 何も起こらないか、アニメーションがハングする
// 正しい
func playerViewController(
_ playerViewController: AVPlayerViewController,
restoreUserInterfaceForPictureInPictureStopWithCompletionHandler completionHandler: @escaping (Bool) -> Void
) {
present(playerViewController, animated: false) {
completionHandler(true)
}
}
してはいけないこと: SwiftUIビューのinitでAVPlayerを作成する
プレーヤーをすぐに作成すると、パフォーマンスの問題が発生します。SwiftUIはビューを複数回再作成する可能性があります。
// 間違い: すべてのビューinitで作成される
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) }
}
}
レビューチェックリスト
- オーディオセッションカテゴリが
.playback、mode: .moviePlaybackに設定されている - Info.plistの
UIBackgroundModesにaudioバックグラウンドモードが追加されている -
AVPlayerViewControllerがサブクラス化されていない - PiP復元デリゲートメソッドが実装され、
completionHandler(true)を呼び出している - SwiftUIでは
AVPlayerが.taskに延期されている(即座に作成されていない) - インラインプレーヤーで
canStartPictureInPictureAutomaticallyFromInlineが設定されている -
requiresLinearPlaybackは必要な広告/法的セグメント中のみ切り替えられている - AirPlayサポートのために
AVPlayerでallowsExternalPlaybackが有効になっている - 字幕言語の制限が実際のメディアトラックでテストされている
- ビデオグラビティが適切に設定されている(
.resizeAspectvs.resizeAspectFill) - プレーヤービューを表示する前に
isReadyForDisplayが監視されている - ネットワークストリーミングコンテンツのエラーハンドリング(HLS障害、タイムアウト)
参考資料
- 高度なパターン(カスタムプレーヤーUI、インタースティシャル、バックグラウンド再生、エラーハンドリング): references/avkit-patterns.md
- AVKitフレームワーク
- AVPlayerViewController
- VideoPlayer (SwiftUI)