YouTube SDKを利用してインライン再生を実装する

##今回実装すること

今回はアプリでもよくあるインライン再生を実装してみたいと思います。

実装する機能は次のとおりです。
・インライン再生
・画面上では一つの動画しか再生できない(一つ再生させればもう一つはポーズする)

##完成イメージ
![simulator_screenshot_F236E870-EA2F-45E6-B463-F41475148AAB.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/552896/bdf2d59a-d495-ac4f-99ea-b8f5708eacdc.png)



##画面の構造
![スクリーンショット 2021-12-04 23.23.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/552896/78b4dc52-aa97-5e89-281b-371e54dba3d3.png)
![スクリーンショット 2021-12-04 23.19.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/552896/96a768a5-6830-cdeb-633a-93bee6e98dcc.png)

上記のように動画を貼りたいUIViewを用意してYTPlayerViewを継承させます。
その上にUIImageViewを動画のサムネイルとして配置し、さらに上からUIButtonを再生ボタンとして配置します。

##実際のコード

まずは今回使うYouTubeSDKをインストールします
``pod 'youtube-ios-player-helper'``

次に実際にコードを見ていきましょう。

```viewController.swift
import UIKit
import youtube_ios_player_helper

class ViewController: UIViewController {
    
    // MARK: - Properties
    
    @IBOutlet weak var tableView: UITableView!
    var playingVideos: [YTPlayerView] = []

    // MARK: - LifeCycle

    override func viewDidLoad() {
        super.viewDidLoad()
        
        tableView.dataSource = self
        tableView.rowHeight = 290
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }
}

// MARK: - UITableViewDataSource

extension ViewController: UITableViewDataSource {
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 10
    }
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! Cell
        cell.delegate = self
        return cell
    }
    
    func tableView(_ tableView: UITableView, didEndDisplaying cell: UITableViewCell, forRowAt indexPath: IndexPath) {
        pauseVideo(cell as! Cell)
    }
}

// MARK: - CellDelegate

extension ViewController: CellDelegate {
    func pauseVideo(at: Int) {
        playingVideos[at].pauseVideo()
        removePlayingList()
    }
    
    func appendPlayingList(_ playerView: YTPlayerView) {
        playingVideos.append(playerView)
    }
    
    func removePlayingList() {
        if !playingVideos.isEmpty {
            //　他に再生中の動画がある場合
            playingVideos.remove(at: 0)
        }
    }
    
    func isExist(_ playerView: YTPlayerView) {
        if !playingVideos.isEmpty {
            //　他に再生中の動画がある場合
            pauseVideo(at: 0)
            removePlayingList()
            DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
                self.appendPlayingList(playerView)
            }
        } else {
            // 他に再生中の動画がない場合
            appendPlayingList(playerView)
        }
    }
    
    func pauseVideo(_ cell: Cell) {
        cell.playerView.pauseVideo()
        print("DEBUG: ビデオがストップしました")
    }
}

```

コードの簡単な解説をしていきたいと思います。

今回は画面上では一つの動画しか再生されないようにするため他の動画を再生したら現在再生中の動画を止める必要があります。
そのため、再生中の動画を**playingVideos**という配列で定義しておきます。

今回は配列を用意しているのですが、画面上で最大一つの動画しか再生させないため、**最大値は１**になります。
処理は再生している場合配列に１を入れ、一時停止または停止した場合、**配列を空**にします。
他の動画を再生する場合、現在配列が**空かどうかを判定**して、空であれば１を入れ、すでに１が入っている場合は再生中の動画があるということなので、その動画を一時停止し（配列を空にして）動画を再生（配列に１を入れる）といった流れです。


```Cell.swift
import UIKit
import AlamofireImage
import youtube_ios_player_helper

protocol CellDelegate: AnyObject {
    func pauseVideo(_ cell: Cell)
    func appendPlayingList(_ playerView: YTPlayerView)
    func removePlayingList()
    func isExist(_ playerView: YTPlayerView)
}

class Cell: UITableViewCell, YTPlayerViewDelegate {
    
    // MARK: - Properties
        
    @IBOutlet weak var playerView: YTPlayerView!
    @IBOutlet weak var thumbnailImageView: UIImageView!
    @IBOutlet weak var playButton: UIButton!

    weak var delegate: CellDelegate?
    
    // MARK: - Lifecycle
    
    override func awakeFromNib() {
        super.awakeFromNib()

        playerView.delegate = self
        
        // 動画の読み込みを行う
        // ビデオIDはyoutubeのurlの最後の部分を入れます。ex) https://www.youtube.com/watch?v=krVvD84IkQ8の場合はkrVvD84IkQ8
        playerView.load(withVideoId: ビデオID, playerVars: ["playsinline": 1, "controls": 0, "modestbranding": 0, "autoplay": 1, "rel": 0, "enablejsapi": 1])
        thumbnailImageView.af.setImage(withURL: URL(string: "https://img.youtube.com/vi/FzKUVEfxw44/0.jpg")!)
    }
    
    // MARK: - Actions
    
    @IBAction func tapPlay(sender: UIButton) {
        playerView.playVideo()
    }

    // MARK: - YTPlayerViewDelegate

    // 動画の状態が変化したときに呼ばれるメソッド
    func playerView(_ playerView: YTPlayerView, didChangeTo state: YTPlayerState) {
        switch state {
        case .ended:
            delegate?.removePlayingList()
        case .playing:
            playButton.isHidden = true
            thumbnailImageView.isHidden = true
            delegate?.isExist(playerView)
        case .paused:
            playButton.isHidden = false
            delegate?.removePlayingList()
        case .buffering:
            // 動画の読み込み中に呼ばれる
            break
        default:
            break
        }
    }
}
```

こちらはcell側のコードです。
動画の状態が変化するとそれに準したdelegateが呼ばれるようになっています。


##最後に
本記事は冗長な説明を省いて要点だけを説明しました。
これからもお時間がない人でもサクッと読んでいただけますと幸いです。