Communitygithub.com

AVKit|JordanCoin/iOSスキルコレクション

AVKitを使用してメディア再生体験を構築します。AVPlayerViewControllerを使った動画プレーヤーの追加、ピクチャーインピクチャーの有効化、AirPlayによるメディアルーティング、SwiftUIのVideoPlayerビューの使用、トランスポートコントロールの設定、字幕・クローズドキャプションの表示、またはシステムUIと連携したAVFoundation再生の統合時に使用します。

iOSスキルコレクション とは?

このスキルは、AVFoundationをベースにした高レベルなメディア再生UIを提供するAVKitフレームワークの包括的なガイドです。AVPlayerViewController、SwiftUIのVideoPlayer、ピクチャーインピクチャー(PiP)、AirPlay、トランスポートコントロール、字幕・クローズドキャプションなどの主要機能を、Swift 6.3 / iOS 26+をターゲットに詳細に解説しています。各機能のセットアップ手順、コード例、ベストプラクティスに加えて、よくある間違いとその回避方法、レビューチェックリストが含まれており、開発者がAVKitを安全かつ効率的にアプリに統合できるよう支援します。高度なパターン(カスタムプレーヤーUI、インタースティシャル、バックグラウンド再生、エラーハンドリング)については、references/avkit-patterns.mdを参照するよう促しています。

対応~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/JordanCoin/ios-skills-collection/tree/HEAD/skills/dpearson2699--avkit

お気に入りのAIに質問する

このエージェントスキルを事前に読み込んだ状態で新しいチャットを開きます。

ドキュメント

AVKit

AVFoundation上に構築された高レベルなメディア再生UI。システム標準の動画プレーヤー、ピクチャーインピクチャー(PiP)、AirPlayルーティング、トランスポートコントロール、字幕・キャプション表示を提供します。Swift 6.3 / iOS 26+を対象としています。

目次

セットアップ

オーディオセッション設定

再生を開始する前に、オーディオセッションとバックグラウンドモードを設定します。これがないと、PiPやバックグラウンドオーディオは静かに失敗します。

  1. Info.plistのUIBackgroundModesにaudioバックグラウンドモードを追加する
  2. オーディオセッションカテゴリを.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を直接使用します。

前提条件

  1. オーディオセッションカテゴリが.playbackに設定されていること(セットアップ参照)
  2. 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が有効になっている
  • 字幕言語の制限が実際のメディアトラックでテストされている
  • ビデオグラビティが適切に設定されている(.resizeAspect vs .resizeAspectFill)
  • プレーヤービューを表示する前にisReadyForDisplayが監視されている
  • ネットワークストリーミングコンテンツのエラーハンドリング(HLS障害、タイムアウト)

参考資料

Individual skills in this repo

This repo contains 11 individual skills — each has its own dedicated page.

JordanCoin/ios-skills-collection

Interact with GitHub using the `gh` CLI. Use `gh issue`, `gh pr`, `gh run`, and `gh api` for issues, PRs, CI runs, and advanced queries. Use when the user asks about GitHub issues, pull requests, workflows, or wants to interact with GitHub repositories from the command line — including tasks like check CI status, create PR, list issues, or query the GitHub API.

JordanCoin/ios-skills-collection

Integrate and optimize Core ML models in iOS apps for on-device machine learning inference. Covers model loading (.mlmodelc, .mlpackage), predictions with auto-generated classes and MLFeatureProvider, compute unit configuration (CPU, GPU, Neural Engine), MLTensor, VNCoreMLRequest, MLComputePlan, multi-model pipelines, and deployment strategies. Use when loading Core ML models, making predictions, configuring compute units, or profiling model performance.

JordanCoin/ios-skills-collection

Implement, review, or improve maps and location features in iOS/macOS apps using MapKit and CoreLocation. Use when working with Map views, annotations, markers, polylines, user location tracking, geocoding, reverse geocoding, search/autocomplete, directions and routes, geofencing, region monitoring, CLLocationUpdate async streams, or location authorization flows. Also use when working with maps, coordinates, addresses, places, directions, distance calculations, or location-based features in Swift apps.

JordanCoin/ios-skills-collection

Display and manipulate PDF documents using PDFKit. Use when embedding PDFView to show PDF files, creating or modifying PDFDocument instances, adding annotations (highlights, notes, signatures), extracting text with PDFSelection, navigating pages, generating thumbnails, filling PDF forms, or wrapping PDFView in SwiftUI.

JordanCoin/ios-skills-collection

Implement, review, or improve in-app tips and onboarding using Apple's TipKit framework. Use when adding feature discovery tooltips, onboarding flows, contextual tips, first-run experiences, coach marks, or working with Tip protocol, TipView, popoverTip, tip rules, tip events, or feature education UI.

JordanCoin/ios-skills-collection

When the user wants to optimize their Google Play Store listing — title, short description, full description, keywords, ratings, or Play Store-specific features. Use when the user mentions "Google Play", "Android", "Play Store", "Play Console", "short description", "full description indexed", "Google Play ASO", or wants Google Play-specific keyword, creative, or ratings strategy. For iOS App Store optimization, see aso-audit and metadata-optimization.

JordanCoin/ios-skills-collection

When the user wants to implement, optimize, or use App Clips for app discovery and conversion. Use when the user mentions "App Clip", "app clip code", "mini app", "instant app", "App Clip card", "App Clip link", "no download required", "instant experience", or wants to understand how App Clips appear in App Store search. For general App Store discoverability, see aso-audit. For marketing campaigns, see ua-campaign.

JordanCoin/ios-skills-collection

When the user wants to plan a launch strategy for a new app or major update. Also use when the user mentions "app launch", "launch plan", "launch checklist", "pre-launch", "launch day", or "how to launch my app". For ongoing ASO after launch, see aso-audit. For paid acquisition during launch, see ua-campaign.

JordanCoin/ios-skills-collection

When the user wants to analyze their own app's actual performance data from App Store Connect — real downloads, revenue, IAP, subscriptions, trials, or country breakdowns synced via Appeeky Connect. Use when the user asks about "my downloads", "my revenue", "how is my app performing", "ASC data", "sales and trends", "my subscription numbers", "App Store Connect metrics", or wants to compare periods or top markets. For third-party app estimates, see app-analytics. For subscription analytics depth, see monetization-strategy.

JordanCoin/ios-skills-collection

When the user wants a full ASO health audit, review their App Store listing quality, or diagnose why their app isn't ranking. Also use when the user mentions "ASO audit", "ASO score", "why am I not ranking", "listing review", or "optimize my app store page". For keyword-specific research, see keyword-research. For metadata writing, see metadata-optimization.

JordanCoin/ios-skills-collection

Always use when working on any iOS, macOS, Swift, SwiftUI, Xcode, or Apple platform project. Routes to the correct specialized skills based on development phase and task context. This collection contains 210 skills from 28 authors covering the full iOS lifecycle.

関連スキル