iOS14から始めるピクチャ・イン・ピクチャ


1. はじめに

iPadではすでに導入されていたピクチャ・イン・ピクチャがiOSにも対応しました。
これからアプリケーションに導入するに当たっての流れを記述します。

2. ピクチャ・イン・ピクチャについて

ピクチャ・イン・ピクチャを導入することにより、動画再生が他アプリ上でも可能になります。

また、アプリケーションがピクチャ・イン・ピクチャに対応しており、
自動再生が有効になっていればホームボタンを押した時に開始されるようになっています。

2-1. ピクチャ・イン・ピクチャの自動再生について

アプリケーションがピクチャ・イン・ピクチャに対応している場合、
視聴中にホームボタンを押した場合の挙動設定が設定アプリに存在します。

2-1-1. 設定アプリの項目追加箇所

iPhoneを利用している一般的なユーザーはなかなか気付いていないと思います。
設定アプリの2階層程潜った箇所に追加されています。

項目 iOS14 iPadOS13
階層 設定 → 一般 → ピクチャ・イン・ピクチャ 設定 → ホーム画面とDock → マルチタスク
項目名 ピクチャ・イン・ピクチャを自動的に再生する ピクチャインピクチャ
説明文 これをオンにすると、ホームボタンを押したときでもビデオの再生がオーバーレイで続けられます。 同じ

2-1-2. 対応済みアプリの挙動紹介

次にピクチャ・イン・ピクチャ自動再生設定がOn/Offでどのように挙動が変わるか調べてみました。
また、合わせてピクチャ・イン・ピクチャが開始される導線が他に存在しないかも調べてみました。

TVアプリ(apple純正)の挙動
https://apps.apple.com/jp/app/apple-tv/id1174078549

操作 自動再生ON 自動再生OFF
ホームボタンを押下 ホーム画面に遷移し、ピクチャ・イン・ピクチャが始まる ホーム画面に遷移し、再生が停止し音声も止まる※1
ピクチャ・イン・ピクチャボタンを押下 ホーム画面に遷移し、ピクチャ・イン・ピクチャが始まる ホーム画面に遷移し、ピクチャ・イン・ピクチャが始まる
再生画面を下にスワイプダウン 視聴が停止する 視聴が停止する

※1・・・コントロールセンターから音声を再開することが可能

Twitchの挙動

操作 自動再生ON 自動再生OFF
ホームボタンを押下 ホーム画面に遷移し、ピクチャ・イン・ピクチャが始まる ホーム画面に遷移し、再生が停止し音声も止まる※1
ピクチャ・イン・ピクチャボタンを押下 ホーム画面に遷移し、ピクチャ・イン・ピクチャが始まる ホーム画面に遷移し、ピクチャ・イン・ピクチャが始まる
再生画面を下にスワイプダウン 独自実装のミニプレイヤーが始まる 独自実装のミニプレイヤーが始まる

※1・・・コントロールセンターから音声を再開することが可能

2-1-3. 挙動まとめ

ピクチャ・イン・ピクチャをユーザーに開始させる為、
ホームボタンによる操作と、ピクチャ・イン・ピクチャボタンの用意を行う。

ホームボタンを押した時の挙動はOS設定に従う
ピクチャ・イン・ピクチャボタンを押した時は通常通りピクチャ・イン・ピクチャを開始する

3. 実際に導入してみる

3-1. 前提条件

プレイヤーを実装する方法はAVPlayerView, AVPlayerViewController, AVPlayerLayerがある。
ただし、今回はAVPlayerLayerを用いた実装を記述します。

3-2. 導入の対応項目

3-2-1. ピクチャ・イン・ピクチャをサポートしているか確認する

iOS12などOSによりサポートされていない可能性があるのでチェックします。

3-2-2. ピクチャ・イン・ピクチャの再生準備を開始する

ピクチャ・イン・ピクチャの再生を行う旨をOSに伝え、準備を行います。

3-2-3. ピクチャ・イン・ピクチャが再生可能になるまで待機する

OSがピクチャ・イン・ピクチャ再生準備可能になるのを待ちます。

3-2-4. ピクチャ・イン・ピクチャを再生開始する

ピクチャ・イン・ピクチャボタンを用いて開始する場合のみ、開始命令を実行します。

3-3. サンプルアプリを見る

SamplePlayer.swift
func setupPictureInPicture() {
    // Ensure PiP is supported by current device.
    if AVPictureInPictureController.isPictureInPictureSupported() {
        // Create a new controller, passing the reference to the AVPlayerLayer.
        pictureInPictureController = AVPictureInPictureController(playerLayer: playerLayer)
        pictureInPictureController.delegate = self

        pipPossibleObservation = pictureInPictureController.observe(\AVPictureInPictureController.isPictureInPicturePossible,
                                                                    options: [.initial, .new]) { [weak self] _, change in
            // Update the PiP button's enabled state.
            self?.pictureInPictureButton.isEnabled = change.newValue ?? false
        }
    } else {
        // PiP isn't supported by the current device. Disable the PiP button.
        pictureInPictureButton.isEnabled = false
    }
}

@IBAction func togglePictureInPictureMode(_ sender: UIButton) {
    if pictureInPictureController.isPictureInPictureActive {
        pictureInPictureController.stopPictureInPicture()
    } else {
        pictureInPictureController.startPictureInPicture()
    }
}

AVPictureInPictureController.isPictureInPictureSupported()

3-2-1に該当。
ここで対象のデバイスがピクチャ・イン・ピクチャに対応しているか判断しています。

AVPictureInPictureController(playerLayer: playerLayer)

3-2-2に該当。
AVPictureInPictureControllerを作成しています。
このAVPictureInPictureControllerを作成することによってホームボタン押下時に自動で
ピクチャ・イン・ピクチャの再生が開始されるようになります。

AVPictureInPictureController.isPictureInPicturePossible

3-2-3に該当。
AVPictureInPictureControllerを生成してから有効になるまで数秒程遅延があります。
動的に変わるのでサンプルアプリではobserveを利用しているようです。
Rxを使っているのであればRxでパラメータを監視するのはありかと思います。

pictureInPictureController.startPictureInPicture()

3-2-4に該当。
準備が整った後にピクチャ・イン・ピクチャボタンを押下されたときに開始を要求します。
ホームボタンを押され自動再生を開始する場合は不必要です。

3-4. 細かな注意点など

AVPictureInPictureControllerはあらじめて生成しておく

前項で記述したとおりAVPictureInPictureControllerを生成してから有効になるまで遅延があります。
その為、ボタンを押下された後に処理を開始してはレスポンスが悪くなります。

isPictureInPicturePossibleがtrueになるが開始出来ないことがある

現在調査中
AVPictureInPictureControllerを生成時に一瞬trueになるがその後すぐにfalseに戻る。
私の環境でのみ発生している現象かもしれませんが念の為記述します。


以上、ピクチャ・イン・ピクチャの大まかな内容になります。
十数行で導入出来るので検討してみてはいかがでしょうか。