您好,登錄后才能下訂單哦!
android 4.0以上WebView不能全屏播放視頻的解決辦法,很多新手對(duì)此不是很清楚,為了幫助大家解決這個(gè)難題,下面小編將為大家詳細(xì)講解,有這方面需求的人可以來(lái)學(xué)習(xí)下,希望你能有所收獲。
上次鄙人做了一個(gè)簡(jiǎn)單的利用webView實(shí)現(xiàn)的一個(gè)瀏覽器!其中遇到了兩個(gè)問(wèn)題,一個(gè)是將瀏覽器中需要下載的內(nèi)容托管到系統(tǒng)默認(rèn)的下載程序進(jìn)行下載,這個(gè)比較簡(jiǎn)單就不在這里討論了;另一個(gè)問(wèn)題就是我們的Android設(shè)備版本是4.0.3,不能像Android2.3那樣支持全屏播放視頻,這個(gè)問(wèn)題比較糾結(jié),但是經(jīng)過(guò)不斷的摸索,終于解決了這個(gè)問(wèn)題。在這里和大家分享一下解決方法:
1、首先定義一個(gè)VideoEnabledWebView繼承自WebView,復(fù)寫(xiě)其中的loadData,loadDataWithBaseURL,loadUrl方法,道理很簡(jiǎn)單就是在加載url或者js的時(shí)候初始化一些內(nèi)容。見(jiàn)代碼:
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方法是將一個(gè)當(dāng)前的java對(duì)象綁定到一個(gè)javascript上面,使用如下方法
webv.addJavascriptInterface(this, "_VideoEnabledWebView");//this為當(dāng)前對(duì)象,綁定到j(luò)s的_VideoEnabledWebView上面,主要_VideoEnabledWebView的作用域是全局的。這個(gè)部分的內(nèi)容我不是很懂,提供鏈接給大家學(xué)習(xí)下,希望看懂的朋友能教教這個(gè)步驟是干嘛的?。╤ttp://www.oschina.net/code/snippet_232612_8531)
2、定義一個(gè)類VideoEnabledWebChromeClient繼承自WebChromeClient,這個(gè)WebChromeClient中的onShowCustomView方法就是播放網(wǎng)絡(luò)視頻時(shí)會(huì)被調(diào)用的方法,onHideCustomView方法就是視頻播放完成會(huì)被調(diào)用的。其中有個(gè)構(gòu)造函數(shù)需要提出來(lái):
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; }
這個(gè)構(gòu)造函數(shù)中的參數(shù),***個(gè)是webView的父布局,activityVideoView是另外的一個(gè)占滿整個(gè)屏幕的布局,loadingView是播放器的那個(gè)顯示緩沖狀態(tài)的view,webView就是webView啦!
見(jiàn)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>
不多說(shuō)了,直接貼代碼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方法中,當(dāng)這個(gè)方法被調(diào)用,將含有webView的那個(gè)父布局隱藏掉(GONE),然后將***個(gè)參數(shù)view加到布局中。獲取***個(gè)參數(shù)view的子控件childView,進(jìn)行判斷childView是否屬于VideoView(Android 4.0之前是VideoView),如果是Android 4.0之后,則會(huì)執(zhí)行else中的代碼,新建String類型js代碼,然后調(diào)用loadUrl(js)就可以進(jìn)行視頻播放了。其中我個(gè)人不知道它是如何通過(guò)js來(lái)播放視頻的,我覺(jué)得和之前的addJavascriptInterface這個(gè)方法有一定關(guān)系,希望知道如何實(shí)現(xiàn)的能夠指導(dǎo)一下本人。其它的函數(shù)就很好理解了。
看完上述內(nèi)容是否對(duì)您有幫助呢?如果還想對(duì)相關(guān)知識(shí)有進(jìn)一步的了解或閱讀更多相關(guān)文章,請(qǐng)關(guān)注億速云行業(yè)資訊頻道,感謝您對(duì)億速云的支持。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。