WebView中的视频全屏4种方法,特别是腾讯视频,真正解决全屏问题

今天(2016.11.23)再次使用到这个方法,发现在js注入时存在很大可能性的失败,查阅相关资料发现,是js注入时机问题,最好是在页面加载到20%-30%开始注入,所以今天增加一些代码,现在先考虑问题的解决,不考虑性能问题:

 webView.setWebChromeClient(new WebChromeClient() {
            public void onProgressChanged(WebView view, int progress) {
                //循环注入
                if(progress>=20){
                    webView.loadUrl(BrowserJsInject.fullScreenByJs(luyan_bean.videoPath));
                }
            }
        });

测试结果发现该方法对腾讯视频注入成功率差不多为100%,反正我测试的没有发现不成功的问题。

下面是之前写的:

公司app(9私聊)里面有一个页面需要根据网址来播放视频,而且播放的视频一般都是腾讯视频,但外包明确表示他们无法实现,只好自己来解决了,最近拿到源码,花了一天时间(2016.9.9)解决了这个问题。
首先我们应该了解显示条件,首先是在WebView加载视频链接,还有就是全屏和退出全屏按钮必须在网页中,也就是你必须监听到网页全屏事件。

此处我将介绍4种方法,我遇到是使用方法4才能真正解决的全屏问题!

收下来看xml文件: activity_main.xml








添加访问网络的权限:


初始化:

 @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
my_web=(WebView)findViewById(R.id.my_web);
initWebView();
my_web.loadUrl("http://v.qq.com/iframe/player.html?vid=o0318tp1ddw&tiny=0&auto=0");
my_web.addJavascriptInterface(new JsObject(MainActivity.this), "console");
//my_web.loadData(s, "text/html; charset=UTF-8", null);
}
private void initWebView() {
WebSettings ws = my_web.getSettings();
/**
 * setAllowFileAccess 启用或禁止WebView访问文件数据 setBlockNetworkImage 是否显示网络图像
 * setBuiltInZoomControls 设置是否支持缩放 setCacheMode 设置缓冲的模式
 * setDefaultFontSize 设置默认的字体大小 setDefaultTextEncodingName 设置在解码时使用的默认编码
 * setFixedFontFamily 设置固定使用的字体 setJavaSciptEnabled 设置是否支持Javascript
 * setLayoutAlgorithm 设置布局方式 setLightTouchEnabled 设置用鼠标激活被选项
 * setSupportZoom 设置是否支持变焦
 * */
ws.setJavaScriptCanOpenWindowsAutomatically(true);
ws.setPluginState(WebSettings.PluginState.ON);
// settings.setPluginsEnabled(true);
ws.setAllowFileAccess(true);
ws.setLoadWithOverviewMode(true);
ws.setBuiltInZoomControls(true);// 隐藏缩放按钮
ws.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.NARROW_COLUMNS);// 排版适应屏幕
ws.setUseWideViewPort(true);// 可任意比例缩放
ws.setLoadWithOverviewMode(true);// setUseWideViewPort方法设置webview推荐使用的窗口。setLoadWithOverviewMode方法是设置webview加载的页面的模式。
ws.setSavePassword(true);
ws.setSaveFormData(true);// 保存表单数据
ws.setJavaScriptEnabled(true);
ws.setDomStorageEnabled(true);
my_web.setSaveEnabled(false);
ws.setSaveFormData(false);
// 下面的一句话是必须的,必须要打开javaScript不然所做一切都是徒劳的
ws.setJavaScriptEnabled(true);
ws.setSupportZoom(false);
xwebchromeclient = new xWebChromeClient();
//setWebChromeClient主要处理解析,渲染网页等浏览器做的事情
//这个方法必须有,就算类中没有函数也可以,不然视频播放不了
my_web.setWebChromeClient(xwebchromeclient);
//WebChromeClient是辅助WebView处理Javascript的对话框,网站图标,网站title,加载进度等
my_web.setWebViewClient(new xWebViewClientent());
}

1.my_web = (FastWebView) findViewById(R.id.my_web);
my_web.addJavascriptInterface(new JsObject(LuyanDetailActivity.this), "console");

  1. android:configChanges="orientation|keyboardHidden|screenSize"

方法1:
在绑定的WebChromeClient子类中调用onShowCustomView方法,在该方法中进行视频的全屏操作,例如代码:

// 进入全屏的时候  
@Override  
public void onShowCustomView(View view, CustomViewCallback callback) {  
// 赋值给callback  
customViewCallback = callback;  
// 设置webView隐藏  
webview.setVisibility(View.GONE);  
// 声明video,把之后的视频放到这里面去  
FrameLayout video = (FrameLayout) findViewById(R.id.video);  
// 将video放到当前视图中  
video.addView(view);  
// 横屏显示  
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);  
// 设置全屏  
setFullScreen();  
}  
// 退出全屏的时候  
@Override  
public void onHideCustomView() {  
if (customViewCallback != null) {  
// 隐藏掉  
customViewCallback.onCustomViewHidden();  
}  
// 用户当前的首选方向  
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_USER);  
// 退出全屏  
quitFullScreen();  
// 设置WebView可见  
webview.setVisibility(View.VISIBLE);  
}  

但我在使用该方法播放腾讯视频并全屏时,onShowCustomView方法和onHideCustomView方法都不会被调用。

方法2:
向页面注入js事件(例如alert),注入方法参照下面方法3中事件的注入,捕获页面alert,例如代码:

class MyWebChromeClient extends WebChromeClient{  
  
@Override  
public boolean onJsAlert(WebView view, String url, String message,  
JsResult result) {  
  
Builder builder=new AlertDialog.Builder(JqueryMobile01Activity.this);  
builder.setTitle("自定义alert事件");  
builder.show();  
return super.onJsAlert(view, url, message, result);  
}

同方法1一样,我实际操作时,也没有调用onJsAlert事件,

方法3:

参照网址:http://blog.csdn.net/lx331675996/article/details/50634670

JS注入部分:
在网页完成加载时,会回调onPageFinish()方法,在这里可以注入自己需要的js方法。

@Override
public void onPageFinished(WebView view, String url) {
view.loadUrl(BrowserJsInject.fullScreenByJs(url));
}

这里的BrowserJsInject是我自己写的一个对于JS注入的公共类,里面内容如下:

public class BrowserJsInject {

/**
 * Js注入
 * @param url 加载的网页地址
 * @return 注入的js内容,若不是需要适配的网址则返回空javascript
 */
public static String fullScreenByJs(String url){
String refer = referParser(url);
if (null != refer) {
return "javascript:document.getElementsByClassName('" + referParser(url) + "')[0].addEventListener('click',function(){local_obj.playing();return false;});";
}else {
return "javascript:";
}
}

/**
 * 对不同的视频网站分析相应的全屏控件
 * @param url 加载的网页地址
 * @return 相应网站全屏按钮的class标识
 */
public static String referParser(String url){
if (url.contains("letv")) {
return "hv_ico_screen";   //乐视Tv
}else if (url.contains("youku")) {
return "x-zoomin";//优酷
}else if (url.contains("bilibili")) {
return "icon-widescreen"; //bilibili
}else if (url.contains("qq")) {
return "tvp_fullscreen_button";   //腾讯视频
}

return null;
}
}

fullScreen(String url)方法将传入的加载的url,通过referParser(String url)方法分析网站类型。referParser中的返回值都是我个人对于不同网站JS调试后找到的,有问题欢迎指出。然后根据不同的网站注入不同的js,实现对全屏按钮的监听操作。其中js字符串中local_obj为客户端绑定的相关类,用于处理js操作。 至此,JS注入部分结束。

Android客户端处理JS绑定:
当JS注入完成后,网页就已经运行了这个脚本,对相应的全屏按钮实现了监听。 在设置webview的相关属性操作时,可以对设置相应的JS操作:

mMainView.addJavascriptInterface(new Object(){

@JavascriptInterface
public void playing(){
Log.i("video", "=======================");
fullScreen(true);
}

}, "local_obj");

然后,在点击全屏按钮时就会触发fullScreen()方法,这个方法中处理你所需要实现的相关全屏操作。

比如,全屏并手机横屏:

public void fullScreen(){
if (mActivity.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
mCustomScreenLinearLayout.scrollTo(0, 0);
mActivity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
mUrlBarAutoShowManager.flag = false;
mFixedTitlebarContainer.setVisibility(View.GONE);
showFixTitle(false);
mBottomNavigation.hideBottomNav();
mBottomFrameLayout.setVisibility(View.GONE);
}else {
mActivity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
mUrlBarAutoShowManager.flag = true;
mFixedTitlebarContainer.setVisibility(View.VISIBLE);
hideFixTitle(false);
mBottomNavigation.showBottomNav();
mBottomFrameLayout.setVisibility(View.VISIBLE);
}
}

试了一下,还需行不通,因为local_obj.playing();语句在js中会报错,就算把它放到一个html页面中,也是会报错。

方法4:重点;来了

我们在方法3的基础上进行修改,既然local_obj.playing();事件会报错,那我执行一个js自带的事件不就行了,例如:console.log();

下面贴出我自己源代码:

MainActivity.class

package a0.android5.wevview2;

import android.content.Context;
import android.content.pm.ActivityInfo;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.WindowManager;
import android.webkit.JavascriptInterface;
import android.webkit.WebChromeClient;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;

public class MainActivity extends AppCompatActivity {
private WebView my_web;
xWebChromeClient xwebchromeclient;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
my_web=(WebView)findViewById(R.id.my_web);
initWebView();
my_web.loadUrl("http://v.qq.com/iframe/player.html?vid=o0318tp1ddw&tiny=0&auto=0");
my_web.addJavascriptInterface(new JsObject(MainActivity.this), "console");
//my_web.loadData(s, "text/html; charset=UTF-8", null);
}
private void initWebView() {
WebSettings ws = my_web.getSettings();
/**
 * setAllowFileAccess 启用或禁止WebView访问文件数据 setBlockNetworkImage 是否显示网络图像
 * setBuiltInZoomControls 设置是否支持缩放 setCacheMode 设置缓冲的模式
 * setDefaultFontSize 设置默认的字体大小 setDefaultTextEncodingName 设置在解码时使用的默认编码
 * setFixedFontFamily 设置固定使用的字体 setJavaSciptEnabled 设置是否支持Javascript
 * setLayoutAlgorithm 设置布局方式 setLightTouchEnabled 设置用鼠标激活被选项
 * setSupportZoom 设置是否支持变焦
 * */
ws.setJavaScriptCanOpenWindowsAutomatically(true);
ws.setPluginState(WebSettings.PluginState.ON);
// settings.setPluginsEnabled(true);
ws.setAllowFileAccess(true);
ws.setLoadWithOverviewMode(true);
ws.setBuiltInZoomControls(true);// 隐藏缩放按钮
ws.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.NARROW_COLUMNS);// 排版适应屏幕
ws.setUseWideViewPort(true);// 可任意比例缩放
ws.setLoadWithOverviewMode(true);// setUseWideViewPort方法设置webview推荐使用的窗口。setLoadWithOverviewMode方法是设置webview加载的页面的模式。
ws.setSavePassword(true);
ws.setSaveFormData(true);// 保存表单数据
ws.setJavaScriptEnabled(true);
ws.setDomStorageEnabled(true);
my_web.setSaveEnabled(false);
ws.setSaveFormData(false);
// 下面的一句话是必须的,必须要打开javaScript不然所做一切都是徒劳的
ws.setJavaScriptEnabled(true);
ws.setSupportZoom(false);
xwebchromeclient = new xWebChromeClient();
//setWebChromeClient主要处理解析,渲染网页等浏览器做的事情
//这个方法必须有,就算类中没有函数也可以,不然视频播放不了
my_web.setWebChromeClient(xwebchromeclient);
//WebChromeClient是辅助WebView处理Javascript的对话框,网站图标,网站title,加载进度等
my_web.setWebViewClient(new xWebViewClientent());
}
/**
 * 处理Javascript的对话框、网站图标、网站标题以及网页加载进度等
 * @author
 */
public class xWebChromeClient extends WebChromeClient {
}

/**
 * 设置监听事件
 * 处理各种通知、请求等事件
 * @author
 */
 public class JsObject {
Context mContext;

JsObject(Context c) {
mContext = c;
}

   @JavascriptInterface
   public void log(){
   System.out.println("返回结果");
   setFullScreen();
   }
}
/**
 * 设置全屏
 */
private void setFullScreen() {
Log.i("视频全屏-->", "竖屏切换到横屏");
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
// 设置全屏的相关属性,获取当前的屏幕状态,然后设置全屏
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);

// 全屏下的状态码:1098974464
// 窗口下的状态吗:1098973440
}
public class xWebViewClientent extends WebViewClient {

@Override
public void onPageFinished(WebView view, String url) {



view.loadUrl(BrowserJsInject.fullScreenByJs(url));
System.out.println("url1:"+BrowserJsInject.fullScreenByJs(url));
System.out.println("url2"+url);

//view.loadData("", "text/html", "UTF-8");
   // my_web.loadUrl("http://v.qq.com/iframe/player.html?vid=o0318tp1ddw&tiny=0&auto=0");
//view.loadUrl("javascript:alert('123')");
 //view.loadUrl(BrowserJsInject.fullScreenByJs(url));

/*//点击链接时:
view.setWebViewClient(new WebViewClient(){
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {

view.loadUrl(url); //在当前的webview中跳转到新的url
System.out.println("链接--》"+url);
return true;
}
});
启动手机浏览器来打开新的url

webView.setWebViewClient(new WebViewClient(){
 @Override
 public boolean shouldOverrideUrlLoading(WebView view, String url) {

 Intent i = new Intent(Intent.ACTION_VIEW);
 i.setData(Uri.parse(url));
 startActivity(i);
 return true;
 }
 });
*/

/*
view.addJavascriptInterface(new Object(){

@JavascriptInterface
public void playing(){
System.out.println("返回结果");
setFullScreen();
}

}, "local_obj");
view.loadUrl(BrowserJsInject.fullScreenByJs(url));
System.out.println("url1:"+BrowserJsInject.fullScreenByJs(url));
System.out.println("url2"+url);*/
//myJavaScriptInterface = new JavaScriptInterface(this);



}
/**
 * 设置全屏
 */
private void setFullScreen() {
Log.i("视频全屏-->", "竖屏切换到横屏");
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
// 设置全屏的相关属性,获取当前的屏幕状态,然后设置全屏
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);

}


}

}

BrowserJsInject.class

package a0.android5.wevview2;

/**
 * Created by 赵理想on 2016/9/8.
 * 个人邮箱:[email protected]
 * *所属公司:长江期货
 * 该类用途:
 */

public class BrowserJsInject {

/**
 * Js注入
 * @param url 加载的网页地址
 * @return 注入的js内容,若不是需要适配的网址则返回空javascript
 */
public static String fullScreenByJs(String url){
String refer = referParser(url);
if (null != refer) {
String js3="window.onload=function(){document.getElementsByClassName('"
+ referParser(url) + "')[0].addEventListener('click',function(){alert('120');" +
"console.log();" +
"alert('110');})}"
+ ";";


return "javascript:"+js3;
}else {
return "javascript:";
}
}

/**
 * 对不同的视频网站分析相应的全屏控件
 * @param url 加载的网页地址
 * @return 相应网站全屏按钮的class标识
 */
public static String referParser(String url){
if (url.contains("letv")) {
return "hv_ico_screen";   //乐视Tv
}else if (url.contains("youku")) {
return "x-zoomin";//优酷
}else if (url.contains("bilibili")) {
return "icon-widescreen"; //bilibili
}else if (url.contains("qq")) {
return "tvp_fullscreen_button";   //腾讯视频
}

return null;
}
}

特别提醒:
1.别忘记屏幕旋转会影响声明周期,可以参考我的另一篇文章http://www.jianshu.com/p/2370426eac88
2.my_web.addJavascriptInterface(new JsObject(MainActivity.this), "console");
这句必须放在my_web.loadUrl("http://v.qq.com/iframe/player.html?vid=o0318tp1ddw&tiny=0&auto=0");下面。

哈哈,终于成功了!!

你可能感兴趣的:(WebView中的视频全屏4种方法,特别是腾讯视频,真正解决全屏问题)