avkit について
iOS アプリへの AVKit メディア再生機能の組み込みを支援する Swift スキルです。動画プレーヤーを開発する人向けに、システム再生 UI、ピクチャ・イン・ピクチャ、AirPlay、再生操作、字幕を扱います。
主な機能
- 01UIKit と SwiftUI のプレーヤー連携
- 02ピクチャ・イン・ピクチャの設定
- 03AirPlay のルーティング
- 04再生速度とシーク
- 05字幕トラックの選択
活用シーン
- 01全画面またはインライン動画の表示
- 02フローティングウィンドウでの動画再生
- 03AirPlay デバイスへの再生出力
- 04字幕選択と再生速度の提供
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ dpearson2699/ swift-ios-skills --skill avkitインストール後、Claude Code で/avkitを入力して読み込まれたか確認します。
同梱ファイルevals/evals.jsonreferences/avkit-patterns.md
詳細
AVKit
AVFoundation を基盤とする高レベルのメディア再生 UI です。システム標準の ビデオプレーヤー、ピクチャ・イン・ピクチャ、AirPlay ルーティング、再生コントロール、 字幕/キャプション表示を提供します。Swift 6.3 / iOS 26+ を対象としています。
目次
- セットアップ
- AVPlayerViewController
- SwiftUI VideoPlayer
- ピクチャ・イン・ピクチャ
- AirPlay
- 再生コントロールと再生速度
- 字幕とクローズドキャプション
- よくある間違い
- レビュー用チェックリスト
- 参考資料
セットアップ
オーディオセッションの設定
バックグラウンドオーディオ、AirPlay、または PiP に対応する場合、再生アプリには オーディオセッションカテゴリと、それに対応するバックグラウンドモードが必要です。
- 「バックグラウンドモード」>「オーディオ、AirPlay、ピクチャ・イン・ピクチャ」を有効にします(
UIBackgroundModesのaudio値)。 - オーディオセッションカテゴリを
.playbackに設定します。 - 他のオーディオを早まって中断しないよう、再生が始まるまで
setActive(true)の呼び出しを 遅らせます。
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、字幕、フレーム解析を標準で提供します。サブクラス化しないでください。
基本的な表示(フルスクリーン)
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 // Show/hide system controls
playerVC.videoGravity = .resizeAspect // .resizeAspectFill to crop
playerVC.entersFullScreenWhenPlaybackBegins = false
playerVC.exitsFullScreenWhenPlaybackEnds = true
playerVC.updatesNowPlayingInfoCenter = true // Auto-updates MPNowPlayingInfoCenter
contentOverlayView を使うと、動画と再生コントロールの間に、操作を受け付けないビュー(透かし、ロゴ)を
追加できます。
デリゲート
AVPlayerViewControllerDelegate を採用すると、フルスクリーンへの遷移、
PiP のライフサイクルイベント、インターstitial再生、メディア選択の変更に対応できます。
フルスクリーンアニメーションと UI を同期するには、トランジションコーディネーターの
animate(alongsideTransition:completion:) を使用します。
表示準備完了
黒いフラッシュを避けるため、プレーヤーを表示する前に isReadyForDisplay を監視します。
let observation = playerVC.observe(\.isReadyForDisplay) { observed, _ in
if observed.isReadyForDisplay {
// Safe to show the player view
}
}
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 を使うと、他のアプリを使用しながら、フローティングウィンドウで動画を視聴できます。
アプリが適切に設定され、デバイスが PiP に対応しており、現在の AVPlayerItem が
AVPlayer 対応形式の再生可能な動画コンテンツであれば、AVPlayerViewController は PiP を自動的に
サポートします。オーディオのみのアイテム、未対応のコンテナ/コーデック、または動画を表示できる状態になっていないアイテムでは、
アプリとデバイスが正しく設定されていても PiP を利用できない場合があります。カスタムプレーヤー UI では、
AVPictureInPictureController を直接使用します。
前提条件
- オーディオセッションカテゴリが
.playbackに設定されていること(セットアップを参照) - 「バックグラウンドモード」>「オーディオ、AirPlay、ピクチャ・イン・ピクチャ」が有効であること
- オーディオのみのコンテンツではなく、再生可能な動画メディアを含む
AVPlayerItemの準備ができていること - 現在の再生コンテキストで PiP が許可されていること。カスタムプレーヤーでは
isPictureInPicturePossibleを監視します。
標準プレーヤーの PiP
PiP は AVPlayerViewController でデフォルトで有効になっています。自動起動と
インラインから PiP への遷移を制御します。
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
PiP 停止時に UI を復元する
ユーザーが PiP の復元ボタンをタップしたときに、プレーヤーを再表示するデリゲートメソッドを実装します。復元アニメーションをシステムが完了できるよう、完了ハンドラーに true を渡します。
func playerViewController(
_ playerViewController: AVPlayerViewController,
restoreUserInterfaceForPictureInPictureStopWithCompletionHandler completionHandler: @escaping (Bool) -> Void
) {
// Re-present or re-embed the player view controller
present(playerViewController, animated: false) {
completionHandler(true)
}
}
カスタムプレーヤーでの PiP
カスタムプレーヤー UI では、AVPlayerLayer またはサンプルバッファーコンテンツソースとともに AVPictureInPictureController を使用します。PiP UI を作成する前にデバイスの対応状況を確認し、現在の再生コンテキストで PiP を開始する前に、コントローラーの isPictureInPicturePossible を確認します。カスタムプレーヤーとサンプルバッファーを使用した PiP のパターンについては、references/avkit-patterns.md を参照してください。
guard AVPictureInPictureController.isPictureInPictureSupported() else { return }
let pipController = AVPictureInPictureController(playerLayer: playerLayer)
pipController.delegate = self
pipController.canStartPictureInPictureAutomaticallyFromInline = true
// Call this from the user's PiP button action, never automatically.
if pipController.isPictureInPicturePossible {
pipController.startPictureInPicture()
}
広告中のリニア再生
インタースティシャルブレークは、メディアストリーム/マニフェストに含まれている場合(AVFoundation は AVPlayerItem.interstitialTimeRanges を通じて公開します)と、アプリが管理する AVPlayerInterstitialEventController のスケジュールによる場合があります。iOS では interstitialTimeRanges を直接設定しないでください。必須の広告または法的告知の区間でのシークを防ぐ場合に限り、requiresLinearPlayback を使用します。
// During an ad
playerVC.requiresLinearPlayback = true
// After the ad completes
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 // Show video-capable routes first
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 では、標準のトランスポートコントロールと、カスタムのアプリコントロール用の AVPlayer.seek(...) を使用します。isSkipForwardEnabled、isSkipBackwardEnabled、skippingBehavior などの AVPlayerViewController のスキップ動作 API は tvOS 向けです。iOS のプレーヤー実装では使用しないでください。
再生中情報との連携
AVPlayerViewController は、デフォルトで MPNowPlayingInfoCenter を自動的に更新します。再生中情報を手動で管理する場合は、これを無効にします。
playerVC.updatesNowPlayingInfoCenter = false
字幕とクローズドキャプション
メディアに適切なテキストトラックが含まれている場合、AVKit は字幕とクローズドキャプションを自動的に表示します。ユーザーは「設定」>「アクセシビリティ」>「字幕とキャプション」で字幕の設定を変更できます。
プログラムによる選択
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?.select(english, in: group)
}
allowedSubtitleOptionLanguages、requiresFullSubtitles、および AVPlayerViewControllerDelegate のメディア選択コールバックは tvOS 専用です。iOS では、アプリがデフォルトを設定する必要がある場合、アセットの .legible メディア選択グループを読み込み、AVPlayerItem でオプションを選択します。
HLS での字幕トラックの提供
字幕とクローズドキャプションは HLS マニフェストに埋め込まれています。AVKit は、AVAsset の AVMediaSelectionGroup からそれらを読み取ります。ローカルファイルでは、字幕またはクローズドキャプションのトラックを含むメディアを使用するか、AVKit で表示する前に、再生可能なアセットにこれらのトラックを組み込んでください。
よくある間違い
やってはいけないこと:AVPlayerViewController のサブクラス化
Apple は、これがサポート対象外であることを明示しています。将来の OS バージョンで、未定義の動作が発生したり、クラッシュしたりする可能性があります。
// WRONG
class MyPlayerVC: AVPlayerViewController { } // Unsupported
// CORRECT: Use composition with delegation
let playerVC = AVPlayerViewController()
playerVC.delegate = coordinator
やってはいけないこと:PiP 用のオーディオセッション設定を省略する
PiP とバックグラウンド再生は、再生用オーディオセッションのカテゴリと、「オーディオ、AirPlay、およびピクチャ・イン・ピクチャ」のバックグラウンドモードに依存します。
// WRONG: Default audio session
let playerVC = AVPlayerViewController()
playerVC.player = player // PiP won't work
// CORRECT: Configure the category, then activate when playback starts
try AVAudioSession.sharedInstance().setCategory(.playback, mode: .moviePlayback)
try AVAudioSession.sharedInstance().setActive(true)
let playerVC = AVPlayerViewController()
playerVC.player = player
禁止:PiP の復元デリゲートや完了ハンドラーを忘れないでください
restoreUserInterfaceForPictureInPictureStopWithCompletionHandler がないと、
システムはユーザーをプレーヤーに戻せません。
completionHandler(true) を呼び出さないと、システムは不整合な状態になります。
// 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 ビューの init で AVPlayer を作成しないでください
プレーヤーを先行して作成すると、パフォーマンスの問題が発生します。SwiftUI は ビューを複数回再作成する場合があります。
// 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にオーディオ、AirPlay、ピクチャ・イン・ピクチャのバックグラウンドモードを追加している -
AVPlayerViewControllerをサブクラス化していない - アプリ/デバイスの設定だけでなく、サポート対象の動画メディアで PiP をテストしている
- PiP の復元デリゲートメソッドを実装し、
completionHandler(true)を呼び出している - カスタム PiP でデバイスのサポート状況と現在の
isPictureInPicturePossibleの両方を確認している - カスタム PiP を明示的なユーザー操作からのみ開始している
- SwiftUI では
AVPlayerの作成を.taskまで保留している(先行して作成していない) - インラインプレーヤーで
canStartPictureInPictureAutomaticallyFromInlineを設定している -
requiresLinearPlaybackの切り替えを、必要な広告/法的要件のある区間に限っている - iOS のトランスポートコントロールに tvOS 専用のスキップ API を使用していない
- AirPlay が必要な場合に、外部再生を誤って無効にしていない
- 実際のメディアトラックを使って字幕の選択をテストしている
- 適切なビデオグラビティを設定している(
.resizeAspectと.resizeAspectFillのどちらか) - プレーヤービューを表示する前に
isReadyForDisplayを監視している - ネットワークストリーミングコンテンツのエラー処理を実装している(HLS の失敗、タイムアウト)
参考資料
- 高度なパターン(カスタムプレーヤー UI、インタースティシャル、バックグラウンド再生、エラー処理):references/avkit-patterns.md
- AVKit フレームワーク
- AVPlayerViewController
- VideoPlayer(SwiftUI)
- AVPictureInPictureController
- AVRoutePickerView
- AVPlaybackSpeed
- メディア再生用にアプリを設定する
- 標準プレーヤーでピクチャ・イン・ピクチャを採用する
- 標準ユーザーインターフェイスで動画コンテンツを再生する