android 4.0以上WebView不能全屏播放视频的解决办法
上次鄙人做了一个简单的利用webView实现的一个浏览器!其中遇到了两个问题,一个是将浏览器中需要下载的内容托管到系统默认的下载程序进行下载,这个比较简单就不在这里讨论了;另一个问题就是我们的Android设备版本是4.0.3,不能像Android2.3那样支持全屏播放视频,这个问题比较纠结,但是经过不断的摸索,终于解决了这个问题。在这里和大家分享一下解决方法:
1、首先定义一个VideoEnabledWebView继承自WebView,复写其中的loadData,loadDataWithBaseURL,loadUrl方法,道理很简单就是在加载url或者js的时候初始化一些内容。见代码:
- packagecom.danielme.android.webviewdemo;
- importjava.util.Map;
- importandroid.annotation.SuppressLint;
- importandroid.content.Context;
- importandroid.os.Handler;
- importandroid.os.Looper;
- importandroid.util.AttributeSet;
- importandroid.webkit.WebChromeClient;
- importandroid.webkit.WebView;
- publicclassVideoEnabledWebViewextendsWebView
- {
- publicinterfaceToggledFullscreenCallback
- {
- publicvoidtoggledFullscreen(booleanfullscreen);
- }
- privateVideoEnabledWebChromeClientvideoEnabledWebChromeClient;
- privatebooleanaddedJavascriptInterface;
- publicVideoEnabledWebView(Contextcontext)
- {
- super(context);
- addedJavascriptInterface=false;
- }
- publicVideoEnabledWebView(Contextcontext,AttributeSetattrs)
- {
- super(context,attrs);
- addedJavascriptInterface=false;
- }
- publicVideoEnabledWebView(Contextcontext,AttributeSetattrs,intdefStyle)
- {
- super(context,attrs,defStyle);
- addedJavascriptInterface=false;
- }
- /**
- *PassonlyaVideoEnabledWebChromeClientinstance.
- */
- @Override
- @SuppressLint("SetJavaScriptEnabled")
- publicvoidsetWebChromeClient(WebChromeClientclient)
- {
- getSettings().setJavaScriptEnabled(true);
- if(clientinstanceofVideoEnabledWebChromeClient)
- {
- this.videoEnabledWebChromeClient=(VideoEnabledWebChromeClient)client;
- }
- super.setWebChromeClient(client);
- }
- @Override
- publicvoidloadData(Stringdata,StringmimeType,Stringencoding)
- {
- addJavascriptInterface();
- super.loadData(data,mimeType,encoding);
- }
- @Override
- publicvoidloadDataWithBaseURL(StringbaseUrl,Stringdata,
- StringmimeType,Stringencoding,
- StringhistoryUrl)
- {
- addJavascriptInterface();
- super.loadDataWithBaseURL(baseUrl,data,mimeType,encoding,historyUrl);
- }
- @Override
- publicvoidloadUrl(Stringurl)
- {
- addJavascriptInterface();
- super.loadUrl(url);
- }
- @Override
- publicvoidloadUrl(Stringurl,Map<String,String>additionalHttpHeaders)
- {
- addJavascriptInterface();
- super.loadUrl(url,additionalHttpHeaders);
- }
- privatevoidaddJavascriptInterface()
- {
- System.out.println(addedJavascriptInterface);
- if(!addedJavascriptInterface)
- {
- //Addjavascriptinterfacetobecalledwhenthevideoends(mustbedonebeforepageload)
- addJavascriptInterface(newObject()
- {
- },"_VideoEnabledWebView");//MustmatchJavascriptinterfacenameofVideoEnabledWebChromeClient
- 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方法就是视频播放完成会被调用的。其中有个构造函数需要提出来:
- publicVideoEnabledWebChromeClient(ViewactivityNonVideoView,ViewGroupactivityVideoView,ViewloadingView,VideoEnabledWebViewwebView)
- {
- this.activityNonVideoView=activityNonVideoView;
- this.activityVideoView=activityVideoView;
- this.loadingView=loadingView;
- this.webView=webView;
- this.isVideoFullscreen=false;
- }
这个构造函数中的参数,第一个是webView的父布局,activityVideoView是另外的一个占满整个屏幕的布局,loadingView是播放器的那个显示缓冲状态的view,webView就是webView啦!
见activity_main.xml
- <?xmlversion="1.0"encoding="utf-8"?>
- <RelativeLayoutxmlns: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代码。
- packagecom.danielme.android.webviewdemo;
- importandroid.app.ActionBar.LayoutParams;
- importandroid.media.MediaPlayer;
- importandroid.media.MediaPlayer.OnCompletionListener;
- importandroid.media.MediaPlayer.OnErrorListener;
- importandroid.media.MediaPlayer.OnPreparedListener;
- importandroid.view.View;
- importandroid.view.ViewGroup;
- importandroid.webkit.WebChromeClient;
- importandroid.widget.FrameLayout;
- importandroid.widget.VideoView;
- publicclassVideoEnabledWebChromeClientextendsWebChromeClientimplementsOnPreparedListener,OnCompletionListener,OnErrorListener
- {
- publicinterfaceToggledFullscreenCallback
- {
- publicvoidtoggledFullscreen(booleanfullscreen);
- }
- privateViewactivityNonVideoView;
- privateViewGroupactivityVideoView;
- privateViewloadingView;
- privateVideoEnabledWebViewwebView;
- privatebooleanisVideoFullscreen;//Indicatesifthevideoisbeingdisplayedusingacustomview(typicallyfull-screen)
- privateFrameLayoutvideoViewContainer;
- privateCustomViewCallbackvideoViewCallback;
- privateToggledFullscreenCallbacktoggledFullscreenCallback;
- /**
- *Neverusethisconstructoralone.
- *Thisconstructorallowsthisclasstobedefinedasaninlineinnerclassinwhichtheusercanoverridemethods
- */
- publicVideoEnabledWebChromeClient()
- {
- }
- /**
- *BuildsavideoenabledWebChromeClient.
- *@paramactivityNonVideoViewAViewintheactivity'slayoutthatcontainseveryotherviewthatshouldbehiddenwhenthevideogoesfull-screen.
- *@paramactivityVideoViewAViewGroupintheactivity'slayoutthatwilldisplaythevideo.Typicallyyouwouldlikethistofillthewholelayout.
- */
- publicVideoEnabledWebChromeClient(ViewactivityNonVideoView,ViewGroupactivityVideoView)
- {
- this.activityNonVideoView=activityNonVideoView;
- this.activityVideoView=activityVideoView;
- this.loadingView=null;
- this.webView=null;
- this.isVideoFullscreen=false;
- }
- /**
- *BuildsavideoenabledWebChromeClient.
- *@paramactivityNonVideoViewAViewintheactivity'slayoutthatcontainseveryotherviewthatshouldbehiddenwhenthevideogoesfull-screen.
- *@paramactivityVideoViewAViewGroupintheactivity'slayoutthatwilldisplaythevideo.Typicallyyouwouldlikethistofillthewholelayout.
- *@paramloadingViewAViewtobeshownwhilethevideoisloading(typicallyonlyusedinAPIlevel<11).Mustbealreadyinflatedandwithoutaparentview.
- */
- publicVideoEnabledWebChromeClient(ViewactivityNonVideoView,ViewGroupactivityVideoView,ViewloadingView)
- {
- this.activityNonVideoView=activityNonVideoView;
- this.activityVideoView=activityVideoView;
- this.loadingView=loadingView;
- this.webView=null;
- this.isVideoFullscreen=false;
- }
- /**
- *BuildsavideoenabledWebChromeClient.
- *@paramactivityNonVideoViewAViewintheactivity'slayoutthatcontainseveryotherviewthatshouldbehiddenwhenthevideogoesfull-screen.
- *@paramactivityVideoViewAViewGroupintheactivity'slayoutthatwilldisplaythevideo.Typicallyyouwouldlikethistofillthewholelayout.
- *@paramloadingViewAViewtobeshownwhilethevideoisloading(typicallyonlyusedinAPIlevel<11).Mustbealreadyinflatedandwithoutaparentview.
- *@paramwebViewTheownerVideoEnabledWebView.PassingitwillenabletheVideoEnabledWebChromeClienttodetecttheHTML5videoendedeventandexitfull-screen.
- *Note:ThewebpagemustonlycontainonevideotaginorderfortheHTML5videoendedeventtowork.Thiscouldbeimprovedifneeded(seeJavascriptcode).
- */
- publicVideoEnabledWebChromeClient(ViewactivityNonVideoView,ViewGroupactivityVideoView,ViewloadingView,VideoEnabledWebViewwebView)
- {
- this.activityNonVideoView=activityNonVideoView;
- this.activityVideoView=activityVideoView;
- this.loadingView=loadingView;
- this.webView=webView;
- this.isVideoFullscreen=false;
- }
- /**
- *Indicatesifthevideoisbeingdisplayedusingacustomview(typicallyfull-screen)
- *@returntrueitthevideoisbeingdisplayedusingacustomview(typicallyfull-screen)
- */
- publicbooleanisVideoFullscreen()
- {
- returnisVideoFullscreen;
- }
- /**
- *Setacallbackthatwillbefiredwhenthevideostartsorfinishesdisplayingusingacustomview(typicallyfull-screen)
- *@paramcallbackAVideoEnabledWebChromeClient.ToggledFullscreenCallbackcallback
- */
- publicvoidsetOnToggledFullscreen(ToggledFullscreenCallbackcallback)
- {
- this.toggledFullscreenCallback=callback;
- }
- @Override
- publicvoidonShowCustomView(Viewview,CustomViewCallbackcallback)
- {
- if(viewinstanceofFrameLayout)
- {
- //Avideowantstobeshown
- FrameLayoutframeLayout=(FrameLayout)view;
- ViewfocusedChild=frameLayout.getFocusedChild();
- //Savevideorelatedvariables
- this.isVideoFullscreen=true;
- this.videoViewContainer=frameLayout;
- this.videoViewCallback=callback;
- //Hidethenon-videoview,addthevideoview,andshowit
- activityNonVideoView.setVisibility(View.GONE);
- activityVideoView.addView(videoViewContainer,newLayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.MATCH_PARENT));
- activityVideoView.setVisibility(View.VISIBLE);
- if(focusedChildinstanceofVideoView)
- {
- //VideoView(typicallyAPIlevel<11)
- VideoViewvideoView=(VideoView)focusedChild;
- //Handlealltherequiredevents
- videoView.setOnPreparedListener(this);
- videoView.setOnCompletionListener(this);
- videoView.setOnErrorListener(this);
- }
- else//Usuallyandroid.webkit.HTML5VideoFullScreen$VideoSurfaceView,sometimesandroid.webkit.HTML5VideoFullScreen$VideoTextureView
- {
- //HTML5VideoFullScreen(typicallyAPIlevel11+)
- //HandleHTML5videoendedevent
- if(webView!=null&&webView.getSettings().getJavaScriptEnabled())
- {
- //Runjavascriptcodethatdetectsthevideoendandnotifiestheinterface
- Stringjs="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();";//MustmatchJavascriptinterfacenameandmethodofVideoEnableWebView
- }
- js+="}";
- js+="_ytrp_html5_video.addEventListener('ended',_ytrp_html5_video_ended);";
- }
- js+="}";
- webView.loadUrl(js);
- }
- }
- //Notifyfull-screenchange
- if(toggledFullscreenCallback!=null)
- {
- toggledFullscreenCallback.toggledFullscreen(true);
- }
- }
- }
- @Override
- publicvoidonShowCustomView(Viewview,intrequestedOrientation,CustomViewCallbackcallback)//OnlyavailableinAPIlevel14+
- {
- onShowCustomView(view,callback);
- }
- @Override
- publicvoidonHideCustomView()
- {
- //Thismethodmustbemanually(internally)calledonvideoendinthecaseofVideoView(typicallyAPIlevel<11)
- //Thismethodmustbemanually(internally)calledonvideoendinthecaseofHTML5VideoFullScreen(typicallyAPIlevel11+)becauseit'snotalwayscalledautomatically
- //Thismethodmustbemanually(internally)calledonbackkeypress(fromthisclass'onBackPressed()method)
- if(isVideoFullscreen)
- {
- //Hidethevideoview,removeit,andshowthenon-videoview
- activityVideoView.setVisibility(View.GONE);//播放视频的
- activityVideoView.removeView(videoViewContainer);
- activityNonVideoView.setVisibility(View.VISIBLE);
- //Callback
- if(videoViewCallback!=null)videoViewCallback.onCustomViewHidden();
- //Resetvideorelatedvariables
- isVideoFullscreen=false;
- videoViewContainer=null;
- videoViewCallback=null;
- //Notifyfull-screenchange
- if(toggledFullscreenCallback!=null)
- {
- toggledFullscreenCallback.toggledFullscreen(false);
- }
- }
- }
- @Override
- publicViewgetVideoLoadingProgressView()//Videowillstartloading,onlycalledinthecaseofVideoView(typicallyAPIlevel<11)
- {
- if(loadingView!=null)
- {
- loadingView.setVisibility(View.VISIBLE);
- returnloadingView;
- }
- else
- {
- returnsuper.getVideoLoadingProgressView();
- }
- }
- @Override
- publicvoidonPrepared(MediaPlayermp)//Videowillstartplaying,onlycalledinthecaseofVideoView(typicallyAPIlevel<11)
- {
- if(loadingView!=null)
- {
- loadingView.setVisibility(View.GONE);
- }
- }
- @Override
- publicvoidonCompletion(MediaPlayermp)//Videofinishedplaying,onlycalledinthecaseofVideoView(typicallyAPIlevel<11)
- {
- onHideCustomView();
- }
- @Override
- publicbooleanonError(MediaPlayermp,intwhat,intextra)//Errorwhileplayingvideo,onlycalledinthecaseofVideoView(typicallyAPIlevel<11)
- {
- returnfalse;//Byreturningfalse,onCompletion()willbecalled
- }
- /**
- *Notifiestheclassthatthebackkeyhasbeenpressedbytheuser.
- *ThismustbecalledfromtheActivity'sonBackPressed(),andifitreturnsfalse,theactivityitselfshouldhandleit.Otherwisedon'tdoanything.
- *@returnReturnstrueiftheeventwashandled,andfalseifitisnot(videoviewisnotvisible)
- */
- publicbooleanonBackPressed()
- {
- if(isVideoFullscreen)
- {
- onHideCustomView();
- returntrue;
- }
- else
- {
- returnfalse;
- }
- }
- }
主要是onShowCustomView方法中,当这个方法被调用,将含有webView的那个父布局隐藏掉(GONE),然后将第一个参数view加到布局中。获取第一个参数view的子控件childView,进行判断childView是否属于VideoView(Android 4.0之前是VideoView),如果是Android 4.0之后,则会执行else中的代码,新建String类型js代码,然后调用loadUrl(js)就可以进行视频播放了。其中我个人不知道它是如何通过js来播放视频的,我觉得和之前的addJavascriptInterface这个方法有一定关系,希望知道如何实现的能够指导一下本人。其它的函数就很好理解了。
其中多说一句,Android 4.0之前的那个第一个参数view是videoView,Android 4.0之后是那个HTML5VideoFullScreen$VideoSurfaceView
更多相关文章
- Android中怎么破解游戏之修改金币数
- ANDROID Bionic C DOCS
- Symbian学习笔记(8):再尝试着做一个数独游戏
- Android(安卓)Native进程间通信实例—Socket本地通信服务端进程
- Android如何防止apk程序被反编译(尊重劳动成果)
- 又撸一年的代码!尽管我秃头还白发,我还是坚持了
- 【全】Android官网MediaPlayer章节翻译与总结(下)
- Android(安卓)将应用加入到分享列表 跳转的市场选择列表
- android语音即时通讯之录音、播放功能实现代码