LoginSignup
6
5

More than 5 years have passed since last update.

GoogleAPIClientForRESTを使ってYouTubeをiOSで再生

Posted at

はじめに

  • iOSアプリでYouTube動画を再生しようとした場合に、GoogleAPIClientForRESTを使った、まとまった記事がなかったので記述
    • GoogleAPIClientForRESTを使わずにAPI叩いてJSONパースしてる記事が多かった
    • Googleに未ログインで取得できる情報のみに対応
  • RxSwift + RxCocoa を利用

実装サンプル

使うライブラリ

YouTubeiOSPlayerHelper

GoogleAPIClientForREST

  • 動画リストを取得に使う
    • obj-cだけどメンテされてる (公式にはswift版なし)
    • YouTube Data API (v3)をラッピングしている
      • JSONパースするよりは短く記述できる
  • Responseの各データが階層化されており、最初は追うのが大変

RxSwiftとRxCocoa

Nuke

  • 画像表示に利用

R.swift

  • リソースのコード補完

実装

初期設定

  1. YouTube Data API公式の作業を始める前にを参照にYOUR_API_KEYを取得しておく
  2. pod install を実行
  3. YOUR_API_KEY を YouTubeClient/Models/VideoPlaylistFactory.swift に設定

一部解説

取得

VideoPlaylistFactory.swift

  • ここはハマる箇所は少なめ。リクエストを組み立てていくだけ。
  • 検索したい場合は、GTLRYouTubeQuery_SearchListを使う。利用したいAPIと対応したquery見つけるのに少し手間取るかも
    • apiKey以外に、iOS限定のリクエスト制限をかけている場合APIKeyRestrictionBundleIDを設定可能
  • query組み立ては、 公式リファレンスSearch: list を参照
    • query(withPart: "snippet")のpartは "snippet"を指定しないとresponseに個々のビデオ情報が含まれないので注意
    • query.type = "video"としないとプレイリストやチャンネルも返ってくるのでご注意
  • response objectはそのまま扱えず、利用したAPIにあったclassを指定する必要あり
    • 今回の場合は GTLRYouTube_SearchListResponse
    • 最終的には response.itemsにてGTLRYouTube_SearchResultを返す
YouTubeClient/Models/VideoPlaylistFactory.swift
import RxSwift
import GoogleAPIClientForREST

class VideoPlaylistFactory {
    let result = BehaviorSubject<[GTLRYouTube_SearchResult]>(value: [])

    func search(keyward: String = "音楽",
                maxResult: UInt = 50) {

        let query = GTLRYouTubeQuery_SearchList.query(withPart: "snippet")
        query.q = keyward
        query.type = "video"
        query.maxResults = maxResult

        let service = GTLRYouTubeService()
        service.apiKey = "YOUR_API_KEY"

        service.executeQuery(query) { (_, object, error) in
            if error != nil {
                self.result.onNext([])
                return
            }
            guard let response = object as? GTLRYouTube_SearchListResponse,
                let playlist = response.items else {
                    self.result.onNext([])
                    return
            }

            self.result.onNext(playlist)
        }
    }
}

リスト表示(見出し画像やタイトル)

VideoListViewController.swift

  • 今回は、取得した GTLRYouTube_SearchResultに snippetが含まれるので、そちらからサムネイルやタイトルを表示する
    • let entity: GTLRYouTube_SearchResultSnippet = element.snippet の部分
    • 後は、cell側で entity.titleしたり、entity.thumbnails?.medium?.urlしたりして、表示する
  • RxCocoaのTableViewバインディングしてるので、慣れてないとわかりにくいコードかも
YouTubeClient/ViewControllers/VideoListViewController.swift

// 中略

    private func bindData() {
        self.playlistFactory
            .result
            .bind(to: self.tableView.rx.items) { tableView, row, element in

                guard let cell = tableView.dequeueReusableCell(
                    withIdentifier: R.reuseIdentifier.videoListTableViewCell,
                    for: IndexPath(row: row, section: 0)),
                    let entity: GTLRYouTube_SearchResultSnippet = element.snippet else {
                        return UITableViewCell()
                }

                cell.configure(entity: entity)
                return cell
            }
            .disposed(by: disposeBag)
    }

再生

VideoDetailViewController.swift

  • webviewを生成して、Youtube iFrame APIを実行しているだけなので、iFrame APIのリファレンスが参考になる
    • よく使うパラメータは "playsinline": 1 インライン再生かと
  • YTPlayerViewDelegateplayerViewDidBecomeReadyを実装して、ロード終わったら即再生するのも定番
YouTubeClient/ViewControllers/VideoDetailViewController.swift
// 中略
extension VideoDetailViewController {
    private func loadVideo(videoId: String = "") {

        let playerVars = [
            "playsinline": 1
        ]
        self.playerView.load(withVideoId: videoId,
                             playerVars: playerVars)
    }
}

extension VideoDetailViewController: YTPlayerViewDelegate {
    func playerViewDidBecomeReady(_ playerView: YTPlayerView) {
        self.playerView.playVideo()
    }
    func playerView(_ playerView: YTPlayerView, didChangeTo state: YTPlayerState) {}
    func playerView(_ playerView: YTPlayerView, didChangeTo quality: YTPlaybackQuality) {}
    func playerView(_ playerView: YTPlayerView, receivedError error: YTPlayerError) {}
    func playerView(_ playerView: YTPlayerView, didPlayTime playTime: Float) {}
    func playerViewPreferredWebViewBackgroundColor(_ playerView: YTPlayerView) -> UIColor { return .black }
    func playerViewPreferredInitialLoading(_ playerView: YTPlayerView) -> UIView? { return nil }
}

おわりに

  • GoogleAPIClientForREST使ってみたけど、レスポンスやitemsを都度キャストする手間があるのが、もどかしい
  • (リファレンスを参考に)APIのリクエスト・レスポンス構造さえ覚えちゃえば、キャストも迷わず楽になるのでおすすめ
6
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
5