実践Flutter

Flutterでスマホを中心にアプリ制作していきます。

Youtube動画をお手軽再生・YoutubePlayerIFrame

はじめに

今回はFlutterアプリ上でYoutube動画を再生するお手軽な方法を見ていきたいと思います。

最近はYoutube動画も溢れにあふれて、情報収集を効果的にできるかどうかは重要なスキルになりつつありますよね。

そして見たら見っぱなしでもだめですし、いちいち手でキーワードを入れていても大変ですが、かといってレコメンドばかりに頼っていては世界が広がっていきません。

そういうときに情報収集をサポートするツールを作っていくのも面白いと思います。そしてそんなときに自在にYoutube動画の再生をコントロールできるといいですよね。

今回はそういったアプリ作成に必要な要素を見ていきたいと思います。





Youtubeプレイヤー

Youtubeの動画を再生するパッケージを紹介していきます。今現在最もPub Devで人気のYoutubeプレイヤーは「Youtube Player IFrame」です。こちらの使い方を見ていきましょう。

youtube_player_iframe | Flutter Package

パッケージの導入はTerminalで下記コマンドを実行するか:

flutter pub add youtube_player_iframe

あるいはpubspec.yamlに依存性を手動で追記してから:

dependencies:
  youtube_player_iframe: ^2.2.2

(いまこの瞬間2.2.2ですが、変わりうるのでこちらをチェックして最新版を検討してください)

最後に下記を実行します:

flutter pub get

もしパッケージ導入が上の説明で全然わからないよという方は、違うパッケージですが導入の仕方を下記で掴んで戻ってきて下さい:


flutter.gakumon.jp

Androidで動かす場合、もう一つ準備があります。プロジェクトのファイルの「/android/app/src/build.gradle」というファイル(他の場所にもbuild.gradleがポロポロあるので場所に注意!下記の色が変わっている行のところです:


f:id:linkedsort:20211119153703p:plain

このbuild.gradleの中の中段に「minSdkVersion 16」というような記載がないでしょうか。この数字が17以上である必要があります。元から17以上であれば触る必要がないですが、16以下であれば17に変えておきましょう。


f:id:linkedsort:20211119153730p:plain

ちなみにこれを忘れてしまっても丁寧にエラーメッセージで上記の手順を説明してくれますので、慌てずに。ああ、こんな設定あったなとだけ覚えておけば、うっかりしても注意してくれるので安心です。

スクリーンショット

今回つくるサンプルコードの動きをまず見ていきます。

起動すると下記の画面がでてきます:

f:id:linkedsort:20211119154553p:plain:w350


「Play」ボタンを押すと再生されます。ここでChromeによる実行の場合は、一回Youtubeの画面のところをクリックしてあげないとPlayボタンが反応しません。Androidなどではその必要はありません。

f:id:linkedsort:20211119154633p:plain:w350


「Pause」ボタンを押すと、一時停止します。「Play」ボタンを押すとまた再生します。

f:id:linkedsort:20211119154712p:plain:w350

とりあえず固定のYoutubeビデオを再生するサンプルを作っていきます。

サンプルコードをいじれば自由にビデオコンテンツの選択や再生のタイミングなどをいじることができるようになりますよ。


サンプルコード

以下にサンプルコードを示します:

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:youtube_player_iframe/youtube_player_iframe.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    //(1) コントローラーの初期化
    var ytcl = YoutubePlayerController(
      initialVideoId: "CkcvVZZEsJE",
    );

    return MaterialApp(
        debugShowCheckedModeBanner: false,
        //(2) YoutubePlayerControllerProviderでくるみます
        home: YoutubePlayerControllerProvider(
            controller: ytcl,
            child: Scaffold(
                appBar: AppBar(
                  title: const Text("Youtube Player"),
                ),
                body: Container(
                    padding: const EdgeInsets.all(30),
                    child: Column(
                      children: [
                        //(3) プレーヤーiframeで再生枠を作ります
                        const YoutubePlayerIFrame(),
                        const Padding(padding: EdgeInsets.all(30)),
                        Row(
                          mainAxisAlignment: MainAxisAlignment.spaceAround,
                          children: [
                            ElevatedButton(
                                onPressed: () {
                                  //(4) コントローラーのメソッドで操作
                                  ytcl.play();
                                },
                                child: const Text("play")),
                            ElevatedButton(
                                onPressed: () {
                                  ytcl.pause();
                                },
                                child: const Text("pause")),
                          ],
                        )
                      ],
                    )))));
  }
}

コードのポイント

コード中の番号をつけたコメントについてポイントを解説していきます。

(1) Youtubeコントローラの初期化
  //(1) コントローラーの初期化
  var ytcl = YoutubePlayerController(
    initialVideoId: "CkcvVZZEsJE",
  );

Youtubeプレーヤーの初期設定を行っています。

ここでは必須パラメタの初期ビデオIDのみを与えています。このIDはYoutubeのサイトで各動画に割り振られているIDです。


www.youtube.com

こちらのURLは「https://www.youtube.com/watch?v=kn0EOS-ZiIc」ですが、最後のv=のところにある「kn0EOS-ZiIc」がこの動画のIDです。

その他のパラメタは下記のようにparamsにYoutubePlayerParamsというクラスにまとめて与えていきます:

YoutubePlayerController _controller = YoutubePlayerController(
    initialVideoId: 'K18cpp_-gP8',
    params: YoutubePlayerParams(
        playlist: ['nPt8bK2gbaU', 'gQDByCdjUXw'], 
        startAt: Duration(seconds: 30),
        showControls: true,
        showFullscreenButton: true,
    ),
);

上記ではプレイリスト、再生の開始場所、制御パネルの表示、フルスクリーンボタンの表示が設定されています。

主なパラメタは以下の通りです:

パラメタ 意味
autoPlay trueならば最初のビデオの再生を自動的にはじめる
mute trueならばミュート
captionLanguage 字幕の言語。デフォルトは「en」
enableCaption trueならば字幕表示。デフォルトtrue
endAt 再生を終わる時刻を設定
loop 再生をループするかどうか。デフォルトtrue
playlist 初期ビデオの次に続くプレイリストを与える
startAt 再生の開始の時刻を設定
(2) Scaffoldを包む
  //(2) YoutubePlayerControllerProviderでくるみます
  home: YoutubePlayerControllerProvider(
      controller: ytcl,
      child: Scaffold(
          appBar: AppBar( ...

いつもはMaterialAppのイチの子分はScaffoldなのですが、今回はその前にYoutubePlayerControllerProviderが来ているので注意です。とりあえずこうしておきましょう。

(1)で作ったコントローラをここで紐付けています。このコントローラに対して(4)で操作をしていきます。

(3) Youtubeを再生するプレーヤーのウィジェットを置く
   child: Column(
     children: [
        //(3) プレーヤーiframeで再生枠を作ります
        const YoutubePlayerIFrame(),
        ...

YoutubePlayerIFrameのインスタンスを、プレイヤーを置きたい場所に設置します。ここではColumnの中においています。

(4) プレイヤーの操作
  children: [
    ElevatedButton(
      onPressed: () {
        //(4) コントローラーのメソッドで操作
        ytcl.play();
      },
      child: const Text("play")),
    ElevatedButton(
       onPressed: () {
         ytcl.pause();
       },
       child: const Text("pause")),
  ],

(1)で作って(2)でプレイヤーと紐付けたコントローラに対して「Play」や「Pause」などの操作を行っていきます。

直接操作が伝わりますのでObxなどで再描画コントロールする必要はありません。

プレイヤーの操作には、主に以下のものがあります:

メソッド 意味
play() 再生する
pause() 一時停止する
stop() 再生を止め、現在のビデオのデータローディングを中止する
nextVideo() 再生リストの次のビデオに行く
previousVideo() 再生リストの前のビデオに行く
playVideoAt(index) プレイリストのindex番目のビデオに行く
load(id, {startAt,endAt}) 指定されたidのビデオをロードする。開始、終了時間を任意に設定
mute() ミュートする
unMute() ミュート解除
setVolume(volume) ボリューム設定
getThumbnail(id, {quality, webp}) 指定されたidのビデオのサムネイルを取得

色々とサンプルにつっこんで試してみると挙動がわかってくると思います。






おわりに

今回はYoutube動画を再生する人気パッケージについて使い方を解説しました。Androidの設定で少しだけハマりどころがありそうですが、基本的にはお手軽ポンでできましたよね。

アプリの中でYoutube再生したいケースは結構たくさんありますよね。そんなときに気軽に使っていけると思います。


f:id:linkedsort:20211127141456j:plain