Android: WebView での YouTube 再生について(フルスクリーン対応)

Android の WebView は仕様をよく理解していないと、ネイティブ実装よりも大変なケースに遭遇します(しました)。

WebView から Web ページが表示されて一息ついていたら、YouTube が見れないという問題が発生しましたので、その解決方法をメモしておきます。

老婆心ながら、くれぐれもアプリのユーザーエージェントを、あまりにもユニークなものに書き換えたりしないでください。
ユーザーエージェントが大きく変わると、今回の方法でどう頑張っても YouTube は再生できません。これで人生の貴重な3日間を棒に振りました。。。

それではどうぞ。

目次

  • AndroidManifest の設定
  • MainActivity -> WebView の設定
  • MainActivity -> WebChromeClient 拡張クラス
  • MainActivity の全コード
  • レイアウトファイル

AndroidManifest の設定

application の android:hardwareAccelerated を true にします。

AndroidManifest.xml

<application
        android:hardwareAccelerated="true"
        >

MainActivity -> WebView の設定

WebView の設定を以下のようにし、WebChromeClient の拡張クラス(後述)をセットします。

MainActivity.java -> protected void onCreate

myWebView = (WebView) findViewById(R.id.webView);

WebSettings settings = myWebView.getSettings();
settings.setJavaScriptEnabled(true);
settings.setAppCacheEnabled(true);

myWebView.setWebChromeClient(new CustomWebChromeClient());

MainActivity -> WebChromeClient 拡張クラス

WebChromeClient の拡張クラスが必要な理由は YouTube のフルスクリーン表示に対応するためです。

フルスクリーン表示になったとき、 WebVeiw を非表示にしカスタムビューと背景(黒)を表示、フルスクリーンが解除された時に WebVeiw を表示し、カスタムビューと背景(黒)を非表示にする、といった処理を書く必要があります。

WebChromeClient の拡張クラスでオーバーライドするメソッドは次の2つです。

  • public void onShowCustomView
  • public void onHideCustomView

WebChromeClient の拡張クラス CustomWebChromeClient は以下のようになります。

MainActivity.java

class CustomWebChromeClient extends WebChromeClient {

    @Override
    public void onShowCustomView(View view, CustomViewCallback callback) {

        if (videoCustomView != null) {
            callback.onCustomViewHidden();
            return;
        }

        final FrameLayout frame = ((FrameLayout) view);

        final View v1 = frame.getChildAt(0);
        view.setLayoutParams(new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT,
                FrameLayout.LayoutParams.MATCH_PARENT, Gravity.CENTER));
        v1.setOnKeyListener(new View.OnKeyListener() {

            @Override
            public boolean onKey(View v, int keyCode, KeyEvent event) {
                if (keyCode == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_DOWN) {
                    onHideCustomView();
                    return true;
                }
                return false;
            }
        });

        videoCustomView = view;
        customViewContainer.setVisibility(View.VISIBLE);
        customViewContainer.setBackgroundColor(Color.BLACK);
        customViewContainer.bringToFront();
        myWebView.setVisibility(View.GONE);

        customViewContainer.addView(videoCustomView);
    }

    @Override
    public void onHideCustomView() {
        super.onHideCustomView();

        customViewContainer.removeView(videoCustomView);
        videoCustomView = null;
        customViewContainer.setVisibility(View.INVISIBLE);
        myWebView.setVisibility(View.VISIBLE);

    }
}

MainActivity の全コード

完成した MainActivity は以下となります。

MainActivity.java

public class MainActivity extends Activity {

    private WebView myWebView;
    private View containerView;
    private FrameLayout customViewContainer;
    private View videoCustomView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);
        myWebView = (WebView)findViewById(R.id.myWebView);
        customViewContainer = (FrameLayout) findViewById(R.id.customView_frame);

        WebSettings settings = myWebView.getSettings();
        settings.setJavaScriptEnabled(true);
        settings.setAppCacheEnabled(true);

        myWebView.setWebChromeClient(new CustomWebChromeClient());

        myWebView.loadUrl("");
    }

    class CustomWebChromeClient extends WebChromeClient {

        @Override
        public void onShowCustomView(View view, CustomViewCallback callback) {

            if (videoCustomView != null) {
                callback.onCustomViewHidden();
                return;
            }

            final FrameLayout frame = ((FrameLayout) view);

            final View v1 = frame.getChildAt(0);
            view.setLayoutParams(new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT,
                    FrameLayout.LayoutParams.MATCH_PARENT, Gravity.CENTER));
            v1.setOnKeyListener(new View.OnKeyListener() {

                @Override
                public boolean onKey(View v, int keyCode, KeyEvent event) {
                    if (keyCode == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_DOWN) {
                        onHideCustomView();
                        return true;
                    }
                    return false;
                }
            });

            videoCustomView = view;
            customViewContainer.setVisibility(View.VISIBLE);
            customViewContainer.setBackgroundColor(Color.BLACK);
            customViewContainer.bringToFront();
            myWebView.setVisibility(View.GONE);

            customViewContainer.addView(videoCustomView);
        }

        @Override
        public void onHideCustomView() {
            super.onHideCustomView();

            customViewContainer.removeView(videoCustomView);
            videoCustomView = null;
            customViewContainer.setVisibility(View.INVISIBLE);
            myWebView.setVisibility(View.VISIBLE);

        }
    }
}

レイアウトファイル

おまけに layout ファイルも載せておきます。

activity_main.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/main_frame"
    tools:context=".MainActivity">

    <WebView
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:id="@+id/myWebView"
        android:layout_alignParentTop="true"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true"
        android:layout_above="@+id/container"
        android:scrollbars="none" />

    <FrameLayout
        android:id="@+id/customView_frame"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:layout_alignParentRight="true"
        android:layout_alignParentEnd="true"
        android:layout_alignParentBottom="true" />

</RelativeLayout>

まとめ

Android も YouTube も同じ Google なのに、なぜここまでやらなければ WebView から YouTube が再生できないんでしょうか。

今回のソースコードは Android 4.0 以降をターゲットに YouTube の再生に特化したソースコードですが、ここに WebViewClient、ジェスチャー、Android OS の後方互換を考慮した場合、相当カオスなソースコードになります。

Android の WebView の取り扱いにはくれぐれもご注意を。

この記事がみなさんのお役に立ちましたら、下記「Share it」よりブックマークやSNSで共有していただければ幸いです。

siro:chro 無料ゲーム SQN をリリースしました

img_sqn_00

sirochro 初の無料ゲームアプリ SQN をリリースしました。
記事:SQN: iOS 無料ゲームアプリ SQN - Sequential Numbers をリリース
ちょっとした時間に楽しめる完全無料のゲームなっていますので、是非ダウンロードして遊んでみてください。

↓SQN のダウンロードはこちらから

Related Contents

Pickup Contents