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这个方法有一定关系,希望知道如何实现的能够指导一下本人。其它的函数就很好理解了。
其中多说一句,Android 4.0之前的那个第一个参数view是videoView,Android 4.0之后是那个HTML5VideoFullScreen$VideoSurfaceView
android 4.0以上WebView不能全屏播放视频的解决办法相关推荐
- QT视频客户端全屏后视频卡住解决办法
QT编写视频监控客户端全屏后会发生视频卡住的问题,该问题的解决办法是重载showEvent事件,按照如下方式实现. void VideoCanvas::showEvent(QShowEvent * e ...
- Android:Android9.0使用 AndroidVideoCache时不能缓存播放视频的解决
一.问题现象: 项目中使用 https://github.com/danikula/AndroidVideoCache 作为视频缓存组件,但是在9.0手机上无法正常缓存,并且报错: 1.详细错误截图 ...
- Android全屏播放视频~包括刘海屏、隐藏时间状态栏
需求是全屏播放视频,刘海屏上面也要播放. 下面是我实现的方式: 首先创建 CustomVideoView 工具类: import android.annotation.TargetApi; impor ...
- 记一次微信H5全屏播放视频的总结
一.H5场景介绍 需求:在微信里打开一个H5页面,然后点击按钮全屏播放视频,等视频播放完成后,在视频上显示一个跳转按钮,点击按钮跳转到其他的页面. 二.遇到的问题 1.IOS设备微信上,视频不能预加载 ...
- 微信内置浏览器 非全屏播放视频解析
前提条件,接了一个项目要实现在微信公众号里课程播放,而且还有评论功能,视频需要小窗播放. 首先公布解决方案: 感谢知乎上的回答,原版微信内置浏览器 如何小窗不全屏播放视频? 感谢该问题的徐霖同学的回答 ...
- [RK3399][Android7.1] 调试笔记 --- 闪电浏览器全屏播放视频时黑屏
Platform: RK3399 OS: Android 7.1 Kernel: v4.4.83 现象: 使用默认闪电浏览器全屏播放视频时黑屏, error log如下: 08-09 17:19:45 ...
- []转载]微信内置浏览器 非全屏播放视频解析
前提条件,接了一个项目要实现在微信公众号里课程播放,而且还有评论功能,视频需要小窗播放.首先公布解决方案: 感谢知乎上的回答,原版[微信内置浏览器 如何小窗不全屏播放视频?]感谢该问题的徐霖同学的回答 ...
- 微信内置浏览器 非全屏播放视频解析 1
前提条件,接了一个项目要实现在微信公众号里课程播放,而且还有评论功能,视频需要小窗播放. 首先公布解决方案: 感谢知乎上的回答,原版[ 微信内置浏览器 如何小窗不全屏播放视频?] 感谢该问题的徐霖同学 ...
- uniapp 判断页面是否是横竖屏,解决微信小程序video组件全屏播放视频遮盖自定义播放控件问题
如果res.deviceOrientation 等于landscape 的话是竖屏,portrait则是横屏.因为用户每旋转一次屏幕就会触发里面的onShow钩子,因此在页面显示或横竖屏变化都会触发这 ...
最新文章
- golang实践LSM相关内容
- Android中获取系统内存信息以及进程信息-----ActivityManager的使用(一)
- VC++读取图像RGB值
- Python自动化运维——系统性能信息模块
- java中CyclicBarrier的使用
- latex正文显示运算符
- HTML map元素
- 控制使用期限_学校厨房设备延长其使用寿命的方法有哪些呢?
- freemarker【FTL】常见语法大全
- HDU-1716 排列2 组合数
- Elasticsearch 之索引创建原则
- C++单例模式(懒汉模式)实现
- linux配置dhcp超级作用域,Linux DHCP服务器 超级作用域
- 联想用u盘重装系统步骤_联想笔记本u盘重装系统,小编教你联想笔记本怎么使用u盘重装系统...
- JQuery温故而知新
- HTML背景带视频的个人炫酷引导页源码
- GBase 8c基础操作
- linux车机按键学习,linux就该这么学
- 分享一个时间增加的办法
- 同样是IT行业,测试和开发薪资真有这么大差别?
热门文章
- 大林算法计算机控制实验报告,大林算法
- loop指令 c语言,arm汇编loop指令
- Window下VS运行达梦DPI
- C++学习笔记-----std::string的=,+,+=对int,char类型操作数的支持
- 透视映射和射影映射的关系 Perspective and Projectivity
- oracle 增加ora容量_案例:Oracle报错ORA-01144 详解数据文件大小32GB的限制的原因
- c++primer练习13.42
- html代码中本地路径里斜杠 / 和反斜杠 \ 的区别
- ofstream与ate的故事
- CentOS 7.6 下安装 MySQL8.0.13