上次鄙人做了一个简单的利用webView实现的一个浏览器!其中遇到了两个问题,一个是将浏览器中需要下载的内容托管到系统默认的下载程序进行下载,这个比较简单就不在这里讨论了;另一个问题就是我们的Android设备版本是4.0.3,不能像Android2.3那样支持全屏播放视频,这个问题比较纠结,但是经过不断的摸索,终于解决了这个问题。在这里和大家分享一下解决方法:

1、首先定义一个VideoEnabledWebView继承自WebView,复写其中的loadData,loadDataWithBaseURL,loadUrl方法,道理很简单就是在加载url或者js的时候初始化一些内容。见代码:

        
  1. packagecom.danielme.android.webviewdemo;
  2. importjava.util.Map;
  3. importandroid.annotation.SuppressLint;
  4. importandroid.content.Context;
  5. importandroid.os.Handler;
  6. importandroid.os.Looper;
  7. importandroid.util.AttributeSet;
  8. importandroid.webkit.WebChromeClient;
  9. importandroid.webkit.WebView;
  10. publicclassVideoEnabledWebViewextendsWebView
  11. {
  12. publicinterfaceToggledFullscreenCallback
  13. {
  14. publicvoidtoggledFullscreen(booleanfullscreen);
  15. }
  16. privateVideoEnabledWebChromeClientvideoEnabledWebChromeClient;
  17. privatebooleanaddedJavascriptInterface;
  18. publicVideoEnabledWebView(Contextcontext)
  19. {
  20. super(context);
  21. addedJavascriptInterface=false;
  22. }
  23. publicVideoEnabledWebView(Contextcontext,AttributeSetattrs)
  24. {
  25. super(context,attrs);
  26. addedJavascriptInterface=false;
  27. }
  28. publicVideoEnabledWebView(Contextcontext,AttributeSetattrs,intdefStyle)
  29. {
  30. super(context,attrs,defStyle);
  31. addedJavascriptInterface=false;
  32. }
  33. /**
  34. *PassonlyaVideoEnabledWebChromeClientinstance.
  35. */
  36. @Override
  37. @SuppressLint("SetJavaScriptEnabled")
  38. publicvoidsetWebChromeClient(WebChromeClientclient)
  39. {
  40. getSettings().setJavaScriptEnabled(true);
  41. if(clientinstanceofVideoEnabledWebChromeClient)
  42. {
  43. this.videoEnabledWebChromeClient=(VideoEnabledWebChromeClient)client;
  44. }
  45. super.setWebChromeClient(client);
  46. }
  47. @Override
  48. publicvoidloadData(Stringdata,StringmimeType,Stringencoding)
  49. {
  50. addJavascriptInterface();
  51. super.loadData(data,mimeType,encoding);
  52. }
  53. @Override
  54. publicvoidloadDataWithBaseURL(StringbaseUrl,Stringdata,
  55. StringmimeType,Stringencoding,
  56. StringhistoryUrl)
  57. {
  58. addJavascriptInterface();
  59. super.loadDataWithBaseURL(baseUrl,data,mimeType,encoding,historyUrl);
  60. }
  61. @Override
  62. publicvoidloadUrl(Stringurl)
  63. {
  64. addJavascriptInterface();
  65. super.loadUrl(url);
  66. }
  67. @Override
  68. publicvoidloadUrl(Stringurl,Map<String,String>additionalHttpHeaders)
  69. {
  70. addJavascriptInterface();
  71. super.loadUrl(url,additionalHttpHeaders);
  72. }
  73. privatevoidaddJavascriptInterface()
  74. {
  75. System.out.println(addedJavascriptInterface);
  76. if(!addedJavascriptInterface)
  77. {
  78. //Addjavascriptinterfacetobecalledwhenthevideoends(mustbedonebeforepageload)
  79. addJavascriptInterface(newObject()
  80. {
  81. },"_VideoEnabledWebView");//MustmatchJavascriptinterfacenameofVideoEnabledWebChromeClient
  82. addedJavascriptInterface=true;
  83. }
  84. }
  85. }

其中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方法就是视频播放完成会被调用的。其中有个构造函数需要提出来:

        
  1. publicVideoEnabledWebChromeClient(ViewactivityNonVideoView,ViewGroupactivityVideoView,ViewloadingView,VideoEnabledWebViewwebView)
  2. {
  3. this.activityNonVideoView=activityNonVideoView;
  4. this.activityVideoView=activityVideoView;
  5. this.loadingView=loadingView;
  6. this.webView=webView;
  7. this.isVideoFullscreen=false;
  8. }

这个构造函数中的参数,第一个是webView的父布局,activityVideoView是另外的一个占满整个屏幕的布局,loadingView是播放器的那个显示缓冲状态的view,webView就是webView啦!

见activity_main.xml

        
  1. <?xmlversion="1.0"encoding="utf-8"?>
  2. <RelativeLayoutxmlns:android="http://schemas.android.com/apk/res/android"
  3. xmlns:tools="http://schemas.android.com/tools"
  4. android:layout_width="match_parent"
  5. android:layout_height="match_parent"
  6. tools:context=".MainActivity">
  7. <RelativeLayout
  8. android:id="@+id/nonVideoLayout"
  9. android:layout_width="match_parent"
  10. android:layout_height="match_parent">
  11. <com.danielme.android.webviewdemo.VideoEnabledWebView
  12. android:id="@+id/webView"
  13. android:layout_width="match_parent"
  14. android:layout_height="match_parent"/>
  15. </RelativeLayout>
  16. <FrameLayout
  17. android:id="@+id/videoLayout"
  18. android:layout_width="match_parent"
  19. android:layout_height="match_parent">
  20. </FrameLayout>
  21. </RelativeLayout>

不多说了,直接贴代码VideoEnabledWebChromeClient.java代码。

        
  1. packagecom.danielme.android.webviewdemo;
  2. importandroid.app.ActionBar.LayoutParams;
  3. importandroid.media.MediaPlayer;
  4. importandroid.media.MediaPlayer.OnCompletionListener;
  5. importandroid.media.MediaPlayer.OnErrorListener;
  6. importandroid.media.MediaPlayer.OnPreparedListener;
  7. importandroid.view.View;
  8. importandroid.view.ViewGroup;
  9. importandroid.webkit.WebChromeClient;
  10. importandroid.widget.FrameLayout;
  11. importandroid.widget.VideoView;
  12. publicclassVideoEnabledWebChromeClientextendsWebChromeClientimplementsOnPreparedListener,OnCompletionListener,OnErrorListener
  13. {
  14. publicinterfaceToggledFullscreenCallback
  15. {
  16. publicvoidtoggledFullscreen(booleanfullscreen);
  17. }
  18. privateViewactivityNonVideoView;
  19. privateViewGroupactivityVideoView;
  20. privateViewloadingView;
  21. privateVideoEnabledWebViewwebView;
  22. privatebooleanisVideoFullscreen;//Indicatesifthevideoisbeingdisplayedusingacustomview(typicallyfull-screen)
  23. privateFrameLayoutvideoViewContainer;
  24. privateCustomViewCallbackvideoViewCallback;
  25. privateToggledFullscreenCallbacktoggledFullscreenCallback;
  26. /**
  27. *Neverusethisconstructoralone.
  28. *Thisconstructorallowsthisclasstobedefinedasaninlineinnerclassinwhichtheusercanoverridemethods
  29. */
  30. publicVideoEnabledWebChromeClient()
  31. {
  32. }
  33. /**
  34. *BuildsavideoenabledWebChromeClient.
  35. *@paramactivityNonVideoViewAViewintheactivity'slayoutthatcontainseveryotherviewthatshouldbehiddenwhenthevideogoesfull-screen.
  36. *@paramactivityVideoViewAViewGroupintheactivity'slayoutthatwilldisplaythevideo.Typicallyyouwouldlikethistofillthewholelayout.
  37. */
  38. publicVideoEnabledWebChromeClient(ViewactivityNonVideoView,ViewGroupactivityVideoView)
  39. {
  40. this.activityNonVideoView=activityNonVideoView;
  41. this.activityVideoView=activityVideoView;
  42. this.loadingView=null;
  43. this.webView=null;
  44. this.isVideoFullscreen=false;
  45. }
  46. /**
  47. *BuildsavideoenabledWebChromeClient.
  48. *@paramactivityNonVideoViewAViewintheactivity'slayoutthatcontainseveryotherviewthatshouldbehiddenwhenthevideogoesfull-screen.
  49. *@paramactivityVideoViewAViewGroupintheactivity'slayoutthatwilldisplaythevideo.Typicallyyouwouldlikethistofillthewholelayout.
  50. *@paramloadingViewAViewtobeshownwhilethevideoisloading(typicallyonlyusedinAPIlevel<11).Mustbealreadyinflatedandwithoutaparentview.
  51. */
  52. publicVideoEnabledWebChromeClient(ViewactivityNonVideoView,ViewGroupactivityVideoView,ViewloadingView)
  53. {
  54. this.activityNonVideoView=activityNonVideoView;
  55. this.activityVideoView=activityVideoView;
  56. this.loadingView=loadingView;
  57. this.webView=null;
  58. this.isVideoFullscreen=false;
  59. }
  60. /**
  61. *BuildsavideoenabledWebChromeClient.
  62. *@paramactivityNonVideoViewAViewintheactivity'slayoutthatcontainseveryotherviewthatshouldbehiddenwhenthevideogoesfull-screen.
  63. *@paramactivityVideoViewAViewGroupintheactivity'slayoutthatwilldisplaythevideo.Typicallyyouwouldlikethistofillthewholelayout.
  64. *@paramloadingViewAViewtobeshownwhilethevideoisloading(typicallyonlyusedinAPIlevel<11).Mustbealreadyinflatedandwithoutaparentview.
  65. *@paramwebViewTheownerVideoEnabledWebView.PassingitwillenabletheVideoEnabledWebChromeClienttodetecttheHTML5videoendedeventandexitfull-screen.
  66. *Note:ThewebpagemustonlycontainonevideotaginorderfortheHTML5videoendedeventtowork.Thiscouldbeimprovedifneeded(seeJavascriptcode).
  67. */
  68. publicVideoEnabledWebChromeClient(ViewactivityNonVideoView,ViewGroupactivityVideoView,ViewloadingView,VideoEnabledWebViewwebView)
  69. {
  70. this.activityNonVideoView=activityNonVideoView;
  71. this.activityVideoView=activityVideoView;
  72. this.loadingView=loadingView;
  73. this.webView=webView;
  74. this.isVideoFullscreen=false;
  75. }
  76. /**
  77. *Indicatesifthevideoisbeingdisplayedusingacustomview(typicallyfull-screen)
  78. *@returntrueitthevideoisbeingdisplayedusingacustomview(typicallyfull-screen)
  79. */
  80. publicbooleanisVideoFullscreen()
  81. {
  82. returnisVideoFullscreen;
  83. }
  84. /**
  85. *Setacallbackthatwillbefiredwhenthevideostartsorfinishesdisplayingusingacustomview(typicallyfull-screen)
  86. *@paramcallbackAVideoEnabledWebChromeClient.ToggledFullscreenCallbackcallback
  87. */
  88. publicvoidsetOnToggledFullscreen(ToggledFullscreenCallbackcallback)
  89. {
  90. this.toggledFullscreenCallback=callback;
  91. }
  92. @Override
  93. publicvoidonShowCustomView(Viewview,CustomViewCallbackcallback)
  94. {
  95. if(viewinstanceofFrameLayout)
  96. {
  97. //Avideowantstobeshown
  98. FrameLayoutframeLayout=(FrameLayout)view;
  99. ViewfocusedChild=frameLayout.getFocusedChild();
  100. //Savevideorelatedvariables
  101. this.isVideoFullscreen=true;
  102. this.videoViewContainer=frameLayout;
  103. this.videoViewCallback=callback;
  104. //Hidethenon-videoview,addthevideoview,andshowit
  105. activityNonVideoView.setVisibility(View.GONE);
  106. activityVideoView.addView(videoViewContainer,newLayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.MATCH_PARENT));
  107. activityVideoView.setVisibility(View.VISIBLE);
  108. if(focusedChildinstanceofVideoView)
  109. {
  110. //VideoView(typicallyAPIlevel<11)
  111. VideoViewvideoView=(VideoView)focusedChild;
  112. //Handlealltherequiredevents
  113. videoView.setOnPreparedListener(this);
  114. videoView.setOnCompletionListener(this);
  115. videoView.setOnErrorListener(this);
  116. }
  117. else//Usuallyandroid.webkit.HTML5VideoFullScreen$VideoSurfaceView,sometimesandroid.webkit.HTML5VideoFullScreen$VideoTextureView
  118. {
  119. //HTML5VideoFullScreen(typicallyAPIlevel11+)
  120. //HandleHTML5videoendedevent
  121. if(webView!=null&&webView.getSettings().getJavaScriptEnabled())
  122. {
  123. //Runjavascriptcodethatdetectsthevideoendandnotifiestheinterface
  124. Stringjs="javascript:";
  125. js+="_ytrp_html5_video=document.getElementsByTagName('video')[0];";
  126. js+="if(_ytrp_html5_video!==undefined){";
  127. {
  128. js+="function_ytrp_html5_video_ended(){";
  129. {
  130. js+="_ytrp_html5_video.removeEventListener('ended',_ytrp_html5_video_ended);";
  131. js+="_VideoEnabledWebView.notifyVideoEnd();";//MustmatchJavascriptinterfacenameandmethodofVideoEnableWebView
  132. }
  133. js+="}";
  134. js+="_ytrp_html5_video.addEventListener('ended',_ytrp_html5_video_ended);";
  135. }
  136. js+="}";
  137. webView.loadUrl(js);
  138. }
  139. }
  140. //Notifyfull-screenchange
  141. if(toggledFullscreenCallback!=null)
  142. {
  143. toggledFullscreenCallback.toggledFullscreen(true);
  144. }
  145. }
  146. }
  147. @Override
  148. publicvoidonShowCustomView(Viewview,intrequestedOrientation,CustomViewCallbackcallback)//OnlyavailableinAPIlevel14+
  149. {
  150. onShowCustomView(view,callback);
  151. }
  152. @Override
  153. publicvoidonHideCustomView()
  154. {
  155. //Thismethodmustbemanually(internally)calledonvideoendinthecaseofVideoView(typicallyAPIlevel<11)
  156. //Thismethodmustbemanually(internally)calledonvideoendinthecaseofHTML5VideoFullScreen(typicallyAPIlevel11+)becauseit'snotalwayscalledautomatically
  157. //Thismethodmustbemanually(internally)calledonbackkeypress(fromthisclass'onBackPressed()method)
  158. if(isVideoFullscreen)
  159. {
  160. //Hidethevideoview,removeit,andshowthenon-videoview
  161. activityVideoView.setVisibility(View.GONE);//播放视频的
  162. activityVideoView.removeView(videoViewContainer);
  163. activityNonVideoView.setVisibility(View.VISIBLE);
  164. //Callback
  165. if(videoViewCallback!=null)videoViewCallback.onCustomViewHidden();
  166. //Resetvideorelatedvariables
  167. isVideoFullscreen=false;
  168. videoViewContainer=null;
  169. videoViewCallback=null;
  170. //Notifyfull-screenchange
  171. if(toggledFullscreenCallback!=null)
  172. {
  173. toggledFullscreenCallback.toggledFullscreen(false);
  174. }
  175. }
  176. }
  177. @Override
  178. publicViewgetVideoLoadingProgressView()//Videowillstartloading,onlycalledinthecaseofVideoView(typicallyAPIlevel<11)
  179. {
  180. if(loadingView!=null)
  181. {
  182. loadingView.setVisibility(View.VISIBLE);
  183. returnloadingView;
  184. }
  185. else
  186. {
  187. returnsuper.getVideoLoadingProgressView();
  188. }
  189. }
  190. @Override
  191. publicvoidonPrepared(MediaPlayermp)//Videowillstartplaying,onlycalledinthecaseofVideoView(typicallyAPIlevel<11)
  192. {
  193. if(loadingView!=null)
  194. {
  195. loadingView.setVisibility(View.GONE);
  196. }
  197. }
  198. @Override
  199. publicvoidonCompletion(MediaPlayermp)//Videofinishedplaying,onlycalledinthecaseofVideoView(typicallyAPIlevel<11)
  200. {
  201. onHideCustomView();
  202. }
  203. @Override
  204. publicbooleanonError(MediaPlayermp,intwhat,intextra)//Errorwhileplayingvideo,onlycalledinthecaseofVideoView(typicallyAPIlevel<11)
  205. {
  206. returnfalse;//Byreturningfalse,onCompletion()willbecalled
  207. }
  208. /**
  209. *Notifiestheclassthatthebackkeyhasbeenpressedbytheuser.
  210. *ThismustbecalledfromtheActivity'sonBackPressed(),andifitreturnsfalse,theactivityitselfshouldhandleit.Otherwisedon'tdoanything.
  211. *@returnReturnstrueiftheeventwashandled,andfalseifitisnot(videoviewisnotvisible)
  212. */
  213. publicbooleanonBackPressed()
  214. {
  215. if(isVideoFullscreen)
  216. {
  217. onHideCustomView();
  218. returntrue;
  219. }
  220. else
  221. {
  222. returnfalse;
  223. }
  224. }
  225. }

主要是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

更多相关文章

  1. Android中怎么破解游戏之修改金币数
  2. ANDROID Bionic C DOCS
  3. Symbian学习笔记(8):再尝试着做一个数独游戏
  4. Android(安卓)Native进程间通信实例—Socket本地通信服务端进程
  5. Android如何防止apk程序被反编译(尊重劳动成果)
  6. 又撸一年的代码!尽管我秃头还白发,我还是坚持了
  7. 【全】Android官网MediaPlayer章节翻译与总结(下)
  8. Android(安卓)将应用加入到分享列表 跳转的市场选择列表
  9. android语音即时通讯之录音、播放功能实现代码

随机推荐

  1. Android——服务的基本用法之定义一个服
  2. Android(安卓)Stomp客户端
  3. android eclipse中导入framework.jar以及
  4. Android 菜鸟经常遇到的异常
  5. Android bootanimation制作过程
  6. Android折叠列表 ExpandableList
  7. (转摘)Android腾讯微薄客户端开发十三:提
  8. Android一个小球弹跳的例子,希望对大家有
  9. Android获取状态栏高度
  10. Android(安卓)Logcat日志优化