2014-11-23 81 views
4

我想在Amazon Fire TV的WebView中播放YouTube視頻。如何在Amazon Fire TV上的WebView中播放YouTube視頻?

截至今日,在Fire OS上沒有用於播放YouTube視頻的官方API(link),所以我試圖讓它與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; 
} 

回答

1

我寫了一個類來播放消防電視上YouTube視頻,它也適用於Kindle Fire的爲好。如你所知,Youtube沒有官方的api,我們不得不求助於使用網頁瀏覽。我在這裏粘貼的課程除了網頁瀏覽之外還有很多你可能會好奇的內容,所以我會解釋一下。首先,你會發現,當你離開你的活動時,除非你讓它停止,否則YouTube播放的webview將繼續播放。因此,人們告訴其他人的解決方案是使用onPause和pauseTimers方法來關閉視頻。但是亞馬遜強加給我們的是一個令人討厭的問題,那就是音頻和視頻資源沒有發佈到操作系統的其他部分(而不是Google Android Lolipop即Nexus Player的問題)。當資源被您的應用程序佔用時,主要視頻將無法播放,亞馬遜不會允許您的應用程序在商店中播放。他們知道織補好,我們必須使用網頁視圖YouTube的,所以他們給了我們建議的這一點點:

問:我可以使用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

FYI Youtube確實有一個API。 https://developers.google.com/youtube/android/player/ – 2015-07-07 01:26:42

+0

你是否在Fire TV上使用過它? – Ohiovr 2015-07-07 01:27:26

1

有趣的是,我的第一個答案並回答如何與網頁視圖做,但我發現別人的解決方案,它具有使用videoView很多潛在的問題。諷刺的是,我發現它從有機磷農藥的一個鏈接:

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

不像我的解決了這個自動播放。主視頻不受影響。可能還有其他一些粗糙的邊緣,但這很有效。

+0

實際上這可能違反了YouTube的服務條款 – Ohiovr 2015-07-08 21:25:35

相關問題