如何在Amazon Fire TV上的WebView中播放YouTube视频?

时间:2014-11-23 23:12:17

标签: android video webview youtube amazon-fire-tv

我想在亚马逊Fire TV的WebView中播放YouTube视频。

截至今天,在Fire OS(link)上播放YouTube视频没有官方API,因此我尝试使用Android的WebView。在编写的Android WebView文档中,应用程序需要启用硬件加速,并且WebView需要具有WebChromeClient才能播放YouTube视频。

我试图让它工作,但是当我开始播放YouTube视频时,我只看到以全屏模式加载微调器。

这是我的代码:

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

  WebView webview = new WebView(this);
  setContentView(webview);

  webview.getSettings().setBuiltInZoomControls(true);
  webview.getSettings().setJavaScriptEnabled(true);
  webview.setWebChromeClient(new WebChromeClient() {

    @Override
    public void onShowCustomView(View view, CustomViewCallback callback) {
      Log.i("fire-tv", "Show custom view");

      super.onShowCustomView(view, callback);
      if (view instanceof FrameLayout) {
        FrameLayout frame = (FrameLayout) view;
        if (frame.getFocusedChild() instanceof VideoView) {
          VideoView video = (VideoView) frame.getFocusedChild();
          frame.removeView(video);
          setContentView(video);
          video.start();
        }
      }
    }

    @Override
    public void onHideCustomView() {
      Log.i("fire-tv", "Hide custom view.");
    }

  });

  webview.setWebViewClient(new WebViewClient() {

    @Override
    public boolean shouldOverrideUrlLoading(WebView view, String url) {
      return false;
    }

  });

  final String mimeType = "text/html";
  final String encoding = "UTF-8";
  String html = getHTML();

  Log.i("fire-tv", "Loading: " + html);
  webview.loadDataWithBaseURL("", html, mimeType, encoding, "");
}

private String getHTML() {
  String html = "<iframe class=\"youtube-player\" style=\"border: 0; width: 100%; height: 100%; padding:0px; margin:0px\" id=\"ytplayer\" type=\"text/html\" src=\"http://www.youtube.com/embed/"
          + "h11u3vtcpaY"
          + "?fs=0\" frameborder=\"0\">\n"
          + "</iframe>\n";

  return html;
}

2 个答案:

答案 0 :(得分:1)

我写了一堂课,在Fire TV上播放YouTube视频,它也适用于点火。如你所知,Youtube没有官方api,我们不得不求助于使用webview。我在这里粘贴的课程有很多东西,除了你可能很好奇的网页浏览,所以我会解释。首先,你会发现,当你离开你的活动时,YouTube播放的网页浏览会继续播放,除非你告诉它停止。因此人们告诉其他人的解决方案是使用onPause和pauseTimers方法来关闭视频。但亚马逊有一个令人讨厌的问题,那就是音频和视频资源没有发布到操作系统的其他部分(谷歌Android Lolipop即Nexus播放器没有问题)。当您的应用程序保留资源时,主要视频将无法播放,亚马逊将不允许您的应用在商店中播放。他们知道我们必须使用youtube的webview,所以他们给了我们一些建议:

  

问:我可以使用Android WebView和视频的HTML标记吗?   播放?
  答:是的,有限制。硬件媒体资源不是   当您的应用暂停或停止时系统当前发布。至   解决此问题,实现您的onStop()方法显式   杀死你的应用程序:

Amazon source

就像AVGN会说“他们在想什么?”

你不会相信如何强行杀死一个应用程序或活动会导致大量问题..好吧我相信你会这样做,因为你比我自己多了几千分。

我能找到的唯一解决方案是在onPause方法中加载一个非常短的720p高清剪辑(必须有音频!)。我将它与webView.onPause和.pauseTimers结合起来以确保......

如果您使用此课程,请将我的blank.mp4文件复制到您自己的服务器,因为它可能在一个月内没有。

哦,但还有更多。所以你在你的webView中获得了你的YouTube文件......那么一块蛋糕吧?错了,它没有播放,因为在webViews中,Html5通常不会自动播放。你不能将网址设置为自动播放它没有区别。所以我的解决方案是使用java技巧强制点击。它的工作方式是webview不会立即加载,它需要不同的时间才能完全加载。之后,视频会在屏幕中央显示一个播放按钮图标。由于某种原因,小遥控器无法触摸它。但是我输入了代码来强制点击webview的中心。

哦,还有一件事,你必须处理音频焦点或亚马逊将不允许你的应用程序在商店。潘多拉可以在后台玩,除非你处理它。

为什么亚马逊为什么

package com.ohiovr.modules.youtube;


import android.app.Activity;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.graphics.Point;
import android.media.AudioManager;
import android.os.Bundle;
import android.os.SystemClock;
import android.util.Log;
import android.view.Display;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.webkit.WebChromeClient;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;

import java.util.Timer;
import java.util.TimerTask;



public class youtubeKindleWebView extends Activity {


    String StringYoutubeUrl;
    WebView webView;

    AFChangeListener hocusFocus;
    private String videoBlanker = "http://ohiovr.com/church_files/blank.mp4";

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_generic_web_view);

        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);

        webView = (WebView) findViewById(R.id.webView);
        WebSettings webSettings = webView.getSettings();
        webSettings.setBuiltInZoomControls(true);
        webSettings.setJavaScriptEnabled(true);
        webSettings.setAppCacheEnabled(false);
        webSettings.setLoadWithOverviewMode(true);
        webSettings.setUseWideViewPort(true);
        //I used this line in an old and now not used live stream implimentation. It works so I didn't remove it. But you may 
        //want to see if it is nessisary:
        webSettings.setUserAgentString("Mozilla/5.0(iPhone;U;CPUiPhoneOS4_0likeMacOSX;en-us)AppleWebKit/532.9(KHTML,likeGecko)Version/4.0.5Mobile/8A293Safari/6531.22.7");


        webView.setWebViewClient(new Callback()); 
        webView.setWebChromeClient(new WebChromeClient());


    }

    class AFChangeListener implements AudioManager.OnAudioFocusChangeListener {
        @Override
        public void onAudioFocusChange(int focusChange) {
            if (focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT) {
                // mp.pause();
            } else if (focusChange == AudioManager.AUDIOFOCUS_GAIN) {
                //  mp.start();
            } else if (focusChange == AudioManager.AUDIOFOCUS_LOSS) {
                //  mp.stop();
            }
        }
    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        boolean handled = false;

        switch (keyCode) {
            case KeyEvent.KEYCODE_DPAD_CENTER:
                forceAClick();
                break;
            case KeyEvent.KEYCODE_BUTTON_A:
                // ... handle selections
                handled = true;
                break;
            case KeyEvent.KEYCODE_DPAD_LEFT:
                // ... handle left action
                handled = true;
                break;
            case KeyEvent.KEYCODE_DPAD_RIGHT:
                // ... handle right action
                handled = true;
                break;
        }
        return handled || super.onKeyDown(keyCode, event);
    }


    public void forceAClick() {

        Timer timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        Display display = getWindowManager().getDefaultDisplay();
                        Point size = new Point();
                        display.getSize(size);
                        int width = size.x;
                        int height = size.y;


                        // Obtain MotionEvent object
                        long downTime = SystemClock.uptimeMillis();
                        long eventTime = SystemClock.uptimeMillis() + 100;
                        float x = width / 2;
                        float y = height / 2;
                        // List of meta states found here: developer.android.com/reference/android/view/KeyEvent.html#getMetaState()
                        int metaState = 0;
                        MotionEvent motionEvent = MotionEvent.obtain(
                                downTime,
                                eventTime,
                                MotionEvent.ACTION_DOWN,
                                x,
                                y,
                                metaState
                        );

                        webView.setOnTouchListener(new View.OnTouchListener() {
                            @Override
                            public boolean onTouch(View v, MotionEvent event) {
                                Log.d("on touch", "touched down");
                                return false;
                            }
                        });

                        webView.dispatchTouchEvent(motionEvent);
                    }
                });
            }
        }, 1);

        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        Display display = getWindowManager().getDefaultDisplay();
                        Point size = new Point();
                        display.getSize(size);
                        int width = size.x;
                        int height = size.y;


                        // Obtain MotionEvent object
                        long downTime = SystemClock.uptimeMillis();
                        long eventTime = SystemClock.uptimeMillis() + 100;
                        float x = width / 2;
                        float y = height / 2;
                        // List of meta states found here: developer.android.com/reference/android/view/KeyEvent.html#getMetaState()
                        int metaState = 0;
                        MotionEvent motionEvent = MotionEvent.obtain(
                                downTime,
                                eventTime,
                                MotionEvent.ACTION_UP,
                                x,
                                y,
                                metaState
                        );

                        webView.setOnTouchListener(new View.OnTouchListener() {
                            @Override
                            public boolean onTouch(View v, MotionEvent event) {
                                Log.d("on touch", "touched up");
                                return false;
                            }
                        });

                        webView.dispatchTouchEvent(motionEvent);


                    }
                });
            }
        }, 120);


        AudioManager am = (AudioManager) this.getSystemService(Context.AUDIO_SERVICE);
// Request audio focus for playback
        hocusFocus = new AFChangeListener();
        int result = am.requestAudioFocus(hocusFocus, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
    }


    @Override
    public void onResume() {
        super.onResume();
        webView.onResume();
        webView.resumeTimers();
        StringYoutubeUrl = "https://www.youtube.com/embed/" + getIntent().getStringExtra("youtubeID");
        webView.loadUrl(StringYoutubeUrl);
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);

    }


    private class Callback extends WebViewClient {  //this is important for some reason. don't remove!
        @Override
        public boolean shouldOverrideUrlLoading(WebView view, String url) {
            return (false);
        }
    }


    @Override
    protected void onPause() {
        super.onPause();

        webView.loadUrl(videoBlanker);
        webView.pauseTimers();
        webView.onPause();
    }



    /*
    Q: Can I use an Android WebView and the <video> HTML tag for video playback?
    A:
    Yes, with limitations. Hardware media resources are not currently released by the system when your app pauses or stops. To work around this issue implement your onStop() method to explicitly kill the process for your app:

    https://developer.amazon.com/public/solutions/devices/fire-tv/docs/amazon-fire-tv-sdk-frequently-asked-questions
    public void onStop() {
        super.onStop();
        android.os.Process.killProcess(android.os.Process.myPid());
    }
    This issue may also cause instability in the user experience and navigation for your app. The VisualOn SDK is the recommended method for media playback on the device.
    */

    @Override
    protected void onStop() {
        super.onStop();
        // the fascinating part of the next line is that it doesn't kill the application, only this intent
        /////////////  android.os.Process.killProcess(android.os.Process.myPid());
        //no no no! Amazon's advice is bad. It causes a ton of problems.
        //the original problem was that the webview video view frankenhybrid wouldn't release the
        //hardware when the user left the video player.
        //the only and correct solution is to load a very short quiet clip into the webview
        //when the user leaves
        //see onPause for my implementation

    }


}

答案 1 :(得分:1)

有趣的是,我的第一个答案确实回答了如何使用webview进行操作的问题,但我发现其他人使用videoView有很大潜力的解决方案。具有讽刺意味的是,我从其中一个OP链接中找到了它:

https://github.com/kslazarev/android-youtube-player

与我的解决方案不同,它会自动播放。 Prime视频不受影响。可能还有其他一些粗糙的边缘,但效果非常好。