您好,登錄后才能下訂單哦!
android 4.0以上WebView不能全屏播放視頻的解決辦法,很多新手對此不是很清楚,為了幫助大家解決這個難題,下面小編將為大家詳細講解,有這方面需求的人可以來學習下,希望你能有所收獲。
上次鄙人做了一個簡單的利用webView實現的一個瀏覽器!其中遇到了兩個問題,一個是將瀏覽器中需要下載的內容托管到系統默認的下載程序進行下載,這個比較簡單就不在這里討論了;另一個問題就是我們的Android設備版本是4.0.3,不能像Android2.3那樣支持全屏播放視頻,這個問題比較糾結,但是經過不斷的摸索,終于解決了這個問題。在這里和大家分享一下解決方法:
1、首先定義一個VideoEnabledWebView繼承自WebView,復寫其中的loadData,loadDataWithBaseURL,loadUrl方法,道理很簡單就是在加載url或者js的時候初始化一些內容。見代碼:
package com.danielme.android.webviewdemo; import java.util.Map; import android.annotation.SuppressLint; import android.content.Context; import android.os.Handler; import android.os.Looper; import android.util.AttributeSet; import android.webkit.WebChromeClient; import android.webkit.WebView; public class VideoEnabledWebView extends WebView { public interface ToggledFullscreenCallback { public void toggledFullscreen(boolean fullscreen); } private VideoEnabledWebChromeClient videoEnabledWebChromeClient; private boolean addedJavascriptInterface; public VideoEnabledWebView(Context context) { super(context); addedJavascriptInterface = false; } public VideoEnabledWebView(Context context, AttributeSet attrs) { super(context, attrs); addedJavascriptInterface = false; } public VideoEnabledWebView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); addedJavascriptInterface = false; } /** * Pass only a VideoEnabledWebChromeClient instance. */ @Override @SuppressLint ("SetJavaScriptEnabled") public void setWebChromeClient(WebChromeClient client) { getSettings().setJavaScriptEnabled(true); if (client instanceof VideoEnabledWebChromeClient) { this.videoEnabledWebChromeClient = (VideoEnabledWebChromeClient) client; } super.setWebChromeClient(client); } @Override public void loadData(String data, String mimeType, String encoding) { addJavascriptInterface(); super.loadData(data, mimeType, encoding); } @Override public void loadDataWithBaseURL(String baseUrl, String data, String mimeType, String encoding, String historyUrl) { addJavascriptInterface(); super.loadDataWithBaseURL(baseUrl, data, mimeType, encoding, historyUrl); } @Override public void loadUrl(String url) { addJavascriptInterface(); super.loadUrl(url); } @Override public void loadUrl(String url, Map<String, String> additionalHttpHeaders) { addJavascriptInterface(); super.loadUrl(url, additionalHttpHeaders); } private void addJavascriptInterface() { System.out.println(addedJavascriptInterface); if (!addedJavascriptInterface) { // Add javascript interface to be called when the video ends (must be done before page load) addJavascriptInterface(new Object() { }, "_VideoEnabledWebView"); // Must match Javascript interface name of VideoEnabledWebChromeClient addedJavascriptInterface = true; } } }
其中addJavascriptInterface方法是將一個當前的java對象綁定到一個javascript上面,使用如下方法
webv.addJavascriptInterface(this, "_VideoEnabledWebView");//this為當前對象,綁定到js的_VideoEnabledWebView上面,主要_VideoEnabledWebView的作用域是全局的。這個部分的內容我不是很懂,提供鏈接給大家學習下,希望看懂的朋友能教教這個步驟是干嘛的!(http://www.oschina.net/code/snippet_232612_8531)
2、定義一個類VideoEnabledWebChromeClient繼承自WebChromeClient,這個WebChromeClient中的onShowCustomView方法就是播放網絡視頻時會被調用的方法,onHideCustomView方法就是視頻播放完成會被調用的。其中有個構造函數需要提出來:
public VideoEnabledWebChromeClient(View activityNonVideoView, ViewGroup activityVideoView, View loadingView, VideoEnabledWebView webView) { this.activityNonVideoView = activityNonVideoView; this.activityVideoView = activityVideoView; this.loadingView = loadingView; this.webView = webView; this.isVideoFullscreen = false; }
這個構造函數中的參數,***個是webView的父布局,activityVideoView是另外的一個占滿整個屏幕的布局,loadingView是播放器的那個顯示緩沖狀態的view,webView就是webView啦!
見activity_main.xml
<?xml version="1.0" encoding="utf-8"?> <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" tools:context=".MainActivity" > <RelativeLayout android:id="@+id/nonVideoLayout" android:layout_width="match_parent" android:layout_height="match_parent" > <com.danielme.android.webviewdemo.VideoEnabledWebView android:id="@+id/webView" android:layout_width="match_parent" android:layout_height="match_parent" /> </RelativeLayout> <FrameLayout android:id="@+id/videoLayout" android:layout_width="match_parent" android:layout_height="match_parent" > </FrameLayout> </RelativeLayout>
不多說了,直接貼代碼VideoEnabledWebChromeClient.java代碼。
package com.danielme.android.webviewdemo; import android.app.ActionBar.LayoutParams; import android.media.MediaPlayer; import android.media.MediaPlayer.OnCompletionListener; import android.media.MediaPlayer.OnErrorListener; import android.media.MediaPlayer.OnPreparedListener; import android.view.View; import android.view.ViewGroup; import android.webkit.WebChromeClient; import android.widget.FrameLayout; import android.widget.VideoView; public class VideoEnabledWebChromeClient extends WebChromeClient implements OnPreparedListener, OnCompletionListener, OnErrorListener { public interface ToggledFullscreenCallback { public void toggledFullscreen(boolean fullscreen); } private View activityNonVideoView; private ViewGroup activityVideoView; private View loadingView; private VideoEnabledWebView webView; private boolean isVideoFullscreen; // Indicates if the video is being displayed using a custom view (typically full-screen) private FrameLayout videoViewContainer; private CustomViewCallback videoViewCallback; private ToggledFullscreenCallback toggledFullscreenCallback; /** * Never use this constructor alone. * This constructor allows this class to be defined as an inline inner class in which the user can override methods */ public VideoEnabledWebChromeClient() { } /** * Builds a video enabled WebChromeClient. * @param activityNonVideoView A View in the activity's layout that contains every other view that should be hidden when the video goes full-screen. * @param activityVideoView A ViewGroup in the activity's layout that will display the video. Typically you would like this to fill the whole layout. */ public VideoEnabledWebChromeClient(View activityNonVideoView, ViewGroup activityVideoView) { this.activityNonVideoView = activityNonVideoView; this.activityVideoView = activityVideoView; this.loadingView = null; this.webView = null; this.isVideoFullscreen = false; } /** * Builds a video enabled WebChromeClient. * @param activityNonVideoView A View in the activity's layout that contains every other view that should be hidden when the video goes full-screen. * @param activityVideoView A ViewGroup in the activity's layout that will display the video. Typically you would like this to fill the whole layout. * @param loadingView A View to be shown while the video is loading (typically only used in API level <11). Must be already inflated and without a parent view. */ public VideoEnabledWebChromeClient(View activityNonVideoView, ViewGroup activityVideoView, View loadingView) { this.activityNonVideoView = activityNonVideoView; this.activityVideoView = activityVideoView; this.loadingView = loadingView; this.webView = null; this.isVideoFullscreen = false; } /** * Builds a video enabled WebChromeClient. * @param activityNonVideoView A View in the activity's layout that contains every other view that should be hidden when the video goes full-screen. * @param activityVideoView A ViewGroup in the activity's layout that will display the video. Typically you would like this to fill the whole layout. * @param loadingView A View to be shown while the video is loading (typically only used in API level <11). Must be already inflated and without a parent view. * @param webView The owner VideoEnabledWebView. Passing it will enable the VideoEnabledWebChromeClient to detect the HTML5 video ended event and exit full-screen. * Note: The web page must only contain one video tag in order for the HTML5 video ended event to work. This could be improved if needed (see Javascript code). */ public VideoEnabledWebChromeClient(View activityNonVideoView, ViewGroup activityVideoView, View loadingView, VideoEnabledWebView webView) { this.activityNonVideoView = activityNonVideoView; this.activityVideoView = activityVideoView; this.loadingView = loadingView; this.webView = webView; this.isVideoFullscreen = false; } /** * Indicates if the video is being displayed using a custom view (typically full-screen) * @return true it the video is being displayed using a custom view (typically full-screen) */ public boolean isVideoFullscreen() { return isVideoFullscreen; } /** * Set a callback that will be fired when the video starts or finishes displaying using a custom view (typically full-screen) * @param callback A VideoEnabledWebChromeClient.ToggledFullscreenCallback callback */ public void setOnToggledFullscreen(ToggledFullscreenCallback callback) { this.toggledFullscreenCallback = callback; } @Override public void onShowCustomView(View view, CustomViewCallback callback) { if (view instanceof FrameLayout) { // A video wants to be shown FrameLayout frameLayout = (FrameLayout) view; View focusedChild = frameLayout.getFocusedChild(); // Save video related variables this.isVideoFullscreen = true; this.videoViewContainer = frameLayout; this.videoViewCallback = callback; // Hide the non-video view, add the video view, and show it activityNonVideoView.setVisibility(View.GONE); activityVideoView.addView(videoViewContainer, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); activityVideoView.setVisibility(View.VISIBLE); if (focusedChild instanceof VideoView) { // VideoView (typically API level <11) VideoView videoView = (VideoView) focusedChild; // Handle all the required events videoView.setOnPreparedListener(this); videoView.setOnCompletionListener(this); videoView.setOnErrorListener(this); } else // Usually android.webkit.HTML5VideoFullScreen$VideoSurfaceView, sometimes android.webkit.HTML5VideoFullScreen$VideoTextureView { // HTML5VideoFullScreen (typically API level 11+) // Handle HTML5 video ended event if (webView != null && webView.getSettings().getJavaScriptEnabled()) { // Run javascript code that detects the video end and notifies the interface String js = "javascript:"; js += "_ytrp_html5_video = document.getElementsByTagName('video')[0];"; js += "if (_ytrp_html5_video !== undefined) {"; { js += "function _ytrp_html5_video_ended() {"; { js += "_ytrp_html5_video.removeEventListener('ended', _ytrp_html5_video_ended);"; js += "_VideoEnabledWebView.notifyVideoEnd();"; // Must match Javascript interface name and method of VideoEnableWebView } js += "}"; js += "_ytrp_html5_video.addEventListener('ended', _ytrp_html5_video_ended);"; } js += "}"; webView.loadUrl(js); } } // Notify full-screen change if (toggledFullscreenCallback != null) { toggledFullscreenCallback.toggledFullscreen(true); } } } @Override public void onShowCustomView(View view, int requestedOrientation, CustomViewCallback callback) // Only available in API level 14+ { onShowCustomView(view, callback); } @Override public void onHideCustomView() { // This method must be manually (internally) called on video end in the case of VideoView (typically API level <11) // This method must be manually (internally) called on video end in the case of HTML5VideoFullScreen (typically API level 11+) because it's not always called automatically // This method must be manually (internally) called on back key press (from this class' onBackPressed() method) if (isVideoFullscreen) { // Hide the video view, remove it, and show the non-video view activityVideoView.setVisibility(View.GONE);//播放視頻的 activityVideoView.removeView(videoViewContainer); activityNonVideoView.setVisibility(View.VISIBLE); // Call back if (videoViewCallback != null) videoViewCallback.onCustomViewHidden(); // Reset video related variables isVideoFullscreen = false; videoViewContainer = null; videoViewCallback = null; // Notify full-screen change if (toggledFullscreenCallback != null) { toggledFullscreenCallback.toggledFullscreen(false); } } } @Override public View getVideoLoadingProgressView() // Video will start loading, only called in the case of VideoView (typically API level <11) { if (loadingView != null) { loadingView.setVisibility(View.VISIBLE); return loadingView; } else { return super.getVideoLoadingProgressView(); } } @Override public void onPrepared(MediaPlayer mp) // Video will start playing, only called in the case of VideoView (typically API level <11) { if (loadingView != null) { loadingView.setVisibility(View.GONE); } } @Override public void onCompletion(MediaPlayer mp) // Video finished playing, only called in the case of VideoView (typically API level <11) { onHideCustomView(); } @Override public boolean onError(MediaPlayer mp, int what, int extra) // Error while playing video, only called in the case of VideoView (typically API level <11) { return false; // By returning false, onCompletion() will be called } /** * Notifies the class that the back key has been pressed by the user. * This must be called from the Activity's onBackPressed(), and if it returns false, the activity itself should handle it. Otherwise don't do anything. * @return Returns true if the event was handled, and false if it is not (video view is not visible) */ public boolean onBackPressed() { if (isVideoFullscreen) { onHideCustomView(); return true; } else { return false; } } }
主要是onShowCustomView方法中,當這個方法被調用,將含有webView的那個父布局隱藏掉(GONE),然后將***個參數view加到布局中。獲取***個參數view的子控件childView,進行判斷childView是否屬于VideoView(Android 4.0之前是VideoView),如果是Android 4.0之后,則會執行else中的代碼,新建String類型js代碼,然后調用loadUrl(js)就可以進行視頻播放了。其中我個人不知道它是如何通過js來播放視頻的,我覺得和之前的addJavascriptInterface這個方法有一定關系,希望知道如何實現的能夠指導一下本人。其它的函數就很好理解了。
看完上述內容是否對您有幫助呢?如果還想對相關知識有進一步的了解或閱讀更多相關文章,請關注億速云行業資訊頻道,感謝您對億速云的支持。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。