Posted at

GoogleAPIClientForRESTを使ってYouTubeをiOSで再生

More than 1 year has passed since last update.


はじめに


  • iOSアプリでYouTube動画を再生しようとした場合に、GoogleAPIClientForRESTを使った、まとまった記事がなかったので記述


    • GoogleAPIClientForRESTを使わずにAPI叩いてJSONパースしてる記事が多かった

    • Googleに未ログインで取得できる情報のみに対応



  • RxSwift + RxCocoa を利用


実装サンプル

https://github.com/KazukiTanaka/YouTubeClient


使うライブラリ


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のリクエスト・レスポンス構造さえ覚えちゃえば、キャストも迷わず楽になるのでおすすめ