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

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

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

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

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

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

|項目|iOS14|iPadOS13|
|---|---|---|
|階層|設定 → 一般 → ピクチャ・イン・ピクチャ|設定 → ホーム画面とDock → マルチタスク|
|項目名|ピクチャ・イン・ピクチャを自動的に再生する|ピクチャインピクチャ|
|説明文|これをオンにすると、ホームボタンを押したときでもビデオの再生がオーバーレイで続けられます。|同じ|
||<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58367/a4bf7abe-96a4-d249-0066-5847bf2e8354.png" width="300px">|<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58367/b8dd9c5e-2895-17b7-05e2-fb2da9a1a2c7.png" width="400px">|

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

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

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

※1・・・コントロールセンターから<b>音声を再開することが可能</b>。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58367/b6a103ac-042f-b4a1-5ace-acf2d33486e3.png" width="300px"> <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58367/d97bc77f-ca2b-b93b-9e88-88f19a23e171.png" width="300px">

<b>Twitchの挙動</b>

|操作|自動再生ON|自動再生OFF|
|---|---|---|
|ホームボタンを押下|ホーム画面に遷移し、ピクチャ・イン・ピクチャが始まる|ホーム画面に遷移し、再生が停止し音声も止まる※1|
|ピクチャ・イン・ピクチャボタンを押下|ホーム画面に遷移し、ピクチャ・イン・ピクチャが始まる|ホーム画面に遷移し、ピクチャ・イン・ピクチャが始まる|
|再生画面を下にスワイプダウン|独自実装のミニプレイヤーが始まる|独自実装のミニプレイヤーが始まる|
※1・・・コントロールセンターから<b>音声を再開することが可能</b>。

### 2-1-3. 挙動まとめ
ピクチャ・イン・ピクチャをユーザーに開始させる為、
ホームボタンによる操作と、ピクチャ・イン・ピクチャボタンの用意を行う。

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


# 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. サンプルアプリを見る
https://developer.apple.com/documentation/avkit/adopting_picture_in_picture_in_a_custom_player

```swift: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を生成してから有効になるまで<b>数秒程遅延</b>があります。
動的に変わるのでサンプルアプリではobserveを利用しているようです。
Rxを使っているのであればRxでパラメータを監視するのはありかと思います。

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

## 3-4. 細かな注意点など
### AVPictureInPictureControllerはあらじめて生成しておく
前項で記述したとおり`AVPictureInPictureController`を生成してから有効になるまで遅延があります。
その為、ボタンを押下された後に処理を開始してはレスポンスが悪くなります。

### isPictureInPicturePossibleがtrueになるが開始出来ないことがある
<b>現在調査中</b>
`AVPictureInPictureController`を生成時に一瞬`true`になるがその後すぐに`false`に戻る。
私の環境でのみ発生している現象かもしれませんが念の為記述します。

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