• AVPlayerとは
  • 主な機能
  • AVPlayerの基本的な使い方
  • 応用的な使い方
  • AVPlayerの主な特徴・メリット
  • AVPlayer を使用する際の注意点
  • まとめ

AVPlayerとは

AVPlayer は、iOS や macOS において 動画や音楽を再生 するためのフレームワークであるAVFoundation の主要なクラスの一つです。AVPlayer を使用すると、ローカルファイルやインターネット上のストリーミングコンテンツを簡単に再生できます。
AVPlayer は UIKit や SwiftUI で利用可能であり、特に 動画再生アプリ や 音楽プレイヤー の開発に適しています。

主な機能

  • メディアの再生
    • ローカルファイルやリモートURLからの動画・音声の再生
    • シーク(特定の時間にジャンプ)
    • 一時停止、再開、停止
  • トリミングと時間管理
    • 指定した開始時間(startTime)と終了時間(endTime)での再生
    • 再生速度の調整
    • ループ再生の実装
  • バックグラウンド再生
    • アプリがバックグラウンドに移行してもオーディオを継続再生
    • AVAudioSessionと組み合わせることで、他のアプリとの音の管理も可能
  • 字幕と音声トラックの管理
    • 外部字幕の追加・表示
    • 音声トラックの選択
  • HLS(HTTP Live Streaming)のサポート
    • AppleのHTTPライブストリーミング技術に対応
    • ネットワーク環境に応じた最適なビットレート選択

AVPlayerの基本的な使い方

以下は、AVPlayerを使用して動画を再生することが可能な最低限の実装になります。

import SwiftUI
import AVKit

struct VideoPlayerView: View {
    private let player = AVPlayer(url: URL(string: "https://www.example.com/video.mp4")!)
    
    var body: some View {
        VideoPlayer(player: player)
            .onAppear {
                player.play()
            }
            .onDisappear {
                player.pause()
            }
    }
}

特定の時間にシークさせたい場合は、seek()をコールしてください。

let time = CMTime(seconds: 10, preferredTimescale: 600)
player.seek(to: time)

再生速度の調整は、rateに値を設定してください。

player.rate = 1.5 // 1.5倍速で再生

ループ再生させたい場合は、終了通知を受けてseek()で最初に戻ってplay()をコールすることでループ再生が可能となります。

NotificationCenter.default.addObserver(forName: .AVPlayerItemDidPlayToEndTime, object: player.currentItem, queue: .main) { _ in
    player.seek(to: .zero)
    player.play()
}

応用的な使い方

バックグラウンドで音声を再生

Info.plist に “Background Modes” (UIBackgroundModes) を追加し、audio を有効にします。

上記設定後、play()コール前に以下の処理を実行します。

    do {
        let session = AVAudioSession.sharedInstance()
        // setCategoryにて`.playback`を設定することでバックグラウンド再生可能
        // mode、optionは任意。今回はmodeに.default、optionなし
        try session.setCategory(.playback, mode: .default, options: [])
        try session.setActive(true)
        print("Audio session is set for background playback")
    } catch {
        print("Audio session setup failed: \(error)")
    }

以下、バックグラウンド再生するための実装例です。

struct ContentView: View {
    @State private var player = AVPlayer(url: URL(string: "https://example.com/video.mp4")!)

    var body: some View {
        VideoPlayer(player: player)
            .onAppear {
                setupAudioSession()  // ① AudioSession を設定
                player.play()     // ② バックグラウンド再生可能
            }
            .onReceive(NotificationCenter.default.publisher(for: UIApplication.didEnterBackgroundNotification)) { _ in
                try? AVAudioSession.sharedInstance().setActive(true)
            }
    }
}

// AudioSession を設定
func setupAudioSession() {
    do {
        let session = AVAudioSession.sharedInstance()
        // setCategoryにて`.playback`を設定することでバックグラウンド再生可能
        try session.setCategory(.playback, mode: .default, options: [])
        try session.setActive(true)
        print("Audio session is set for background playback")
    } catch {
        print("Audio session setup failed: \(error)")
    }
}

レイアウトをカスタマイズ

SwiftUI の Slider を使って、シークバーを手動で操作できる UI を作りました。

// AVPlayerのインスタンスを作成(指定したURLの動画をロード)
@State private var player = AVPlayer(url: URL(string: "https://example.com/video.mp4")!)
@State private var currentTime: Double = 0   //  現在の再生時間(秒単位)
@State private var duration: Double = 1     //  動画の長さ(秒単位)

var body: some View {
        VStack {
            //  動画プレイヤーの表示
            VideoPlayer(player: player)
                .frame(height: 300)
            
            // シークバー(スライダー)
            Slider(value: $currentTime, in: 0...duration, onEditingChanged: { isDragging in
                if !isDragging { // ドラッグが終わった時にシーク
                    let time = CMTime(seconds: currentTime, preferredTimescale: 600)
                    player.seek(to: time)  // 指定した時間へジャンプ
                }
            })
            .padding()

            // コントロールボタン(巻き戻し、再生、停止、早送り)
            HStack {
                //  先頭へ戻る
                Button(action: { player.seek(to: CMTime(seconds: 0, preferredTimescale: 600)) }) {
                    Image(systemName: "backward.fill")
                        .font(.title)
                }
                Spacer()

                //  再生
                Button(action: { player.play() }) {
                    Image(systemName: "play.fill")
                        .font(.title)
                }
                Spacer()

                // 一時停止
                Button(action: { player.pause() }) {
                    Image(systemName: "pause.fill")
                        .font(.title)
                }
                Spacer()

                // 10秒進む
                Button(action: {
                    let newTime = CMTime(seconds: currentTime + 10, preferredTimescale: 600)
                    player.seek(to: newTime)
                }) {
                    Image(systemName: "forward.fill")
                        .font(.title)
                }
            }
            .padding()
        }
        .onAppear {
            setupPlayerObserver() // 動画の長さと現在の再生時間を監視
            player.play()         //  画面表示時に自動再生
        }
    }
    
    // 動画の長さと現在の再生時間を監視
    private func setupPlayerObserver() {
        guard let duration = player.currentItem?.asset.duration.seconds, duration.isFinite else { return }
        self.duration = duration   // 動画の長さを取得

        // 1秒ごとに再生時間を更新
        player.addPeriodicTimeObserver(forInterval: CMTime(seconds: 1, preferredTimescale: 600), queue: .main) { time in
            self.currentTime = time.seconds
        }
    }

AVPlayerの主な特徴・メリット

  • シンプルなAPI設計
    動画の再生やシークなどの操作が簡単に行えます。
  • バックグラウンド再生に対応
    適切な設定をすれば、アプリを閉じた状態でも音楽や動画を再生できます。
  • カスタマイズ性が高い
    AVPlayerLayer を使用することで、自由にレイアウトやアニメーションを追加できます。
  • HLS(HTTP Live Streaming)のサポート
    AppleのHTTPライブストリーミング技術に対応でき、ネットワーク環境に応じた最適なビットレートを選択することができます。

AVPlayer を使用する際の注意点

メインスレッドで UI の更新を行う

AVPlayer の状態変化を監視する際、UI の更新は必ず メインスレッド (DispatchQueueとかTask) で実装します。

 // DispatchQueue使用の場合
player.addPeriodicTimeObserver(forInterval: CMTime(seconds: 1, preferredTimescale: 600), queue: .main) { time in
    DispatchQueue.main.async {
        self.currentTime = time.seconds // UIを更新(メインスレッドで実行)
    }
}

 // Task使用の場合
player.addPeriodicTimeObserver(forInterval: CMTime(seconds: 1, preferredTimescale: 600), queue: .main) { time in
    Task { @MainActor in
        self.currentTime = time.seconds // UIを更新(メインスレッドで実行)
    }
}

メモリ管理に注意

AVPlayerLooper を使うとメモリリークの原因になりやすいので、不要になったら invalidate() を呼んでください。

looper?.disableLooping()
looper = nil

removeTimeObserverobserverを解放します。
合わせて、replaceCurrentItemにnilを設定することでPlayerItemを解放しましょう。

let observer = player.currentItem?.observe(\.status, options: [.new]) { item, _ in
    if item.status == .failed {
        print("動画の読み込みに失敗しました: \(String(describing: item.error))")
    }
}

// observerとPlayerItem解放
player.removeTimeObserver(observer)
player.pause()
player.replaceCurrentItem(with: nil)

まとめ

AVPlayerは、AVFoundationフレームワークの主要なクラスの一つであり、iOSアプリでの動画や音楽再生に最適なAPIです。
シンプルな API で操作しやすく、ストリーミングやカスタマイズ性にも優れています。
今回紹介した基本的な使い方を活用し、より高度なプレイヤー機能を実装してみましょう。



ギャップロを運営しているアップフロンティア株式会社では、一緒に働いてくれる仲間を随時、募集しています。 興味がある!一緒に働いてみたい!という方は下記よりご応募お待ちしております。
採用情報をみる