WebView中的視頻全屏4種方法,特別是騰訊視頻,真正解決全屏問題

今天(2016.11.23)再次使用到這個(gè)方法,發(fā)現(xiàn)在js注入時(shí)存在很大可能性的失敗,查閱相關(guān)資料發(fā)現(xiàn),是js注入時(shí)機(jī)問題,最好是在頁面加載到20%-30%開始注入,所以今天增加一些代碼,現(xiàn)在先考慮問題的解決,不考慮性能問題:

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

測試結(jié)果發(fā)現(xiàn)該方法對(duì)騰訊視頻注入成功率差不多為100%,反正我測試的沒有發(fā)現(xiàn)不成功的問題。

下面是之前寫的:

公司app(9私聊)里面有一個(gè)頁面需要根據(jù)網(wǎng)址來播放視頻,而且播放的視頻一般都是騰訊視頻,但外包明確表示他們無法實(shí)現(xiàn),只好自己來解決了,最近拿到源碼,花了一天時(shí)間(2016.9.9)解決了這個(gè)問題。
首先我們應(yīng)該了解顯示條件,首先是在WebView加載視頻鏈接,還有就是全屏和退出全屏按鈕必須在網(wǎng)頁中,也就是你必須監(jiān)聽到網(wǎng)頁全屏事件。

此處我將介紹4種方法,我遇到是使用方法4才能真正解決的全屏問題!

收下來看xml文件: 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:id="@+id/activity_main"
android:layout_width="match_parent" android:layout_height="match_parent">
<LinearLayout
android:id="@+id/tv3"
android:layout_width="fill_parent"
android:layout_height="200dp"
android:orientation="vertical" >

<WebView
android:id="@+id/my_web"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#000000" />
</LinearLayout>
</RelativeLayout>

添加訪問網(wǎng)絡(luò)的權(quán)限:

<uses-permission android:name="android.permission.INTERNET"/>

初始化:

 @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訪問文件數(shù)據(jù) setBlockNetworkImage 是否顯示網(wǎng)絡(luò)圖像
 * setBuiltInZoomControls 設(shè)置是否支持縮放 setCacheMode 設(shè)置緩沖的模式
 * setDefaultFontSize 設(shè)置默認(rèn)的字體大小 setDefaultTextEncodingName 設(shè)置在解碼時(shí)使用的默認(rèn)編碼
 * setFixedFontFamily 設(shè)置固定使用的字體 setJavaSciptEnabled 設(shè)置是否支持Javascript
 * setLayoutAlgorithm 設(shè)置布局方式 setLightTouchEnabled 設(shè)置用鼠標(biāo)激活被選項(xiàng)
 * setSupportZoom 設(shè)置是否支持變焦
 * */
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);// 排版適應(yīng)屏幕
ws.setUseWideViewPort(true);// 可任意比例縮放
ws.setLoadWithOverviewMode(true);// setUseWideViewPort方法設(shè)置webview推薦使用的窗口。setLoadWithOverviewMode方法是設(shè)置webview加載的頁面的模式。
ws.setSavePassword(true);
ws.setSaveFormData(true);// 保存表單數(shù)據(jù)
ws.setJavaScriptEnabled(true);
ws.setDomStorageEnabled(true);
my_web.setSaveEnabled(false);
ws.setSaveFormData(false);
// 下面的一句話是必須的,必須要打開javaScript不然所做一切都是徒勞的
ws.setJavaScriptEnabled(true);
ws.setSupportZoom(false);
xwebchromeclient = new xWebChromeClient();
//setWebChromeClient主要處理解析,渲染網(wǎng)頁等瀏覽器做的事情
//這個(gè)方法必須有,就算類中沒有函數(shù)也可以,不然視頻播放不了
my_web.setWebChromeClient(xwebchromeclient);
//WebChromeClient是輔助WebView處理Javascript的對(duì)話框,網(wǎng)站圖標(biāo),網(wǎng)站title,加載進(jìn)度等
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子類中調(diào)用onShowCustomView方法,在該方法中進(jìn)行視頻的全屏操作,例如代碼:

// 進(jìn)入全屏的時(shí)候  
@Override  
public void onShowCustomView(View view, CustomViewCallback callback) {  
// 賦值給callback  
customViewCallback = callback;  
// 設(shè)置webView隱藏  
webview.setVisibility(View.GONE);  
// 聲明video,把之后的視頻放到這里面去  
FrameLayout video = (FrameLayout) findViewById(R.id.video);  
// 將video放到當(dāng)前視圖中  
video.addView(view);  
// 橫屏顯示  
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);  
// 設(shè)置全屏  
setFullScreen();  
}  
// 退出全屏的時(shí)候  
@Override  
public void onHideCustomView() {  
if (customViewCallback != null) {  
// 隱藏掉  
customViewCallback.onCustomViewHidden();  
}  
// 用戶當(dāng)前的首選方向  
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_USER);  
// 退出全屏  
quitFullScreen();  
// 設(shè)置WebView可見  
webview.setVisibility(View.VISIBLE);  
}  

但我在使用該方法播放騰訊視頻并全屏?xí)r,onShowCustomView方法和onHideCustomView方法都不會(huì)被調(diào)用。

方法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一樣,我實(shí)際操作時(shí),也沒有調(diào)用onJsAlert事件,

方法3:

參照網(wǎng)址:http://blog.csdn.net/lx331675996/article/details/50634670

JS注入部分:
在網(wǎng)頁完成加載時(shí),會(huì)回調(diào)onPageFinish()方法,在這里可以注入自己需要的js方法。

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

這里的BrowserJsInject是我自己寫的一個(gè)對(duì)于JS注入的公共類,里面內(nèi)容如下:

public class BrowserJsInject {

/**
 * Js注入
 * @param url 加載的網(wǎng)頁地址
 * @return 注入的js內(nèi)容,若不是需要適配的網(wǎng)址則返回空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:";
}
}

/**
 * 對(duì)不同的視頻網(wǎng)站分析相應(yīng)的全屏控件
 * @param url 加載的網(wǎng)頁地址
 * @return 相應(yīng)網(wǎng)站全屏按鈕的class標(biāo)識(shí)
 */
public static String referParser(String url){
if (url.contains("letv")) {
return "hv_ico_screen";   //樂視Tv
}else if (url.contains("youku")) {
return "x-zoomin";//優(yōu)酷
}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)方法分析網(wǎng)站類型。referParser中的返回值都是我個(gè)人對(duì)于不同網(wǎng)站JS調(diào)試后找到的,有問題歡迎指出。然后根據(jù)不同的網(wǎng)站注入不同的js,實(shí)現(xiàn)對(duì)全屏按鈕的監(jiān)聽操作。其中js字符串中l(wèi)ocal_obj為客戶端綁定的相關(guān)類,用于處理js操作。 至此,JS注入部分結(jié)束。

Android客戶端處理JS綁定:
當(dāng)JS注入完成后,網(wǎng)頁就已經(jīng)運(yùn)行了這個(gè)腳本,對(duì)相應(yīng)的全屏按鈕實(shí)現(xiàn)了監(jiān)聽。 在設(shè)置webview的相關(guān)屬性操作時(shí),可以對(duì)設(shè)置相應(yīng)的JS操作:

mMainView.addJavascriptInterface(new Object(){

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

}, "local_obj");

然后,在點(diǎn)擊全屏按鈕時(shí)就會(huì)觸發(fā)fullScreen()方法,這個(gè)方法中處理你所需要實(shí)現(xiàn)的相關(guān)全屏操作。

比如,全屏并手機(jī)橫屏:

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);
}
}

試了一下,還需行不通,因?yàn)閘ocal_obj.playing();語句在js中會(huì)報(bào)錯(cuò),就算把它放到一個(gè)html頁面中,也是會(huì)報(bào)錯(cuò)。

方法4:重點(diǎn);來了

我們?cè)诜椒?的基礎(chǔ)上進(jìn)行修改,既然local_obj.playing();事件會(huì)報(bào)錯(cuò),那我執(zhí)行一個(gè)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訪問文件數(shù)據(jù) setBlockNetworkImage 是否顯示網(wǎng)絡(luò)圖像
 * setBuiltInZoomControls 設(shè)置是否支持縮放 setCacheMode 設(shè)置緩沖的模式
 * setDefaultFontSize 設(shè)置默認(rèn)的字體大小 setDefaultTextEncodingName 設(shè)置在解碼時(shí)使用的默認(rèn)編碼
 * setFixedFontFamily 設(shè)置固定使用的字體 setJavaSciptEnabled 設(shè)置是否支持Javascript
 * setLayoutAlgorithm 設(shè)置布局方式 setLightTouchEnabled 設(shè)置用鼠標(biāo)激活被選項(xiàng)
 * setSupportZoom 設(shè)置是否支持變焦
 * */
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);// 排版適應(yīng)屏幕
ws.setUseWideViewPort(true);// 可任意比例縮放
ws.setLoadWithOverviewMode(true);// setUseWideViewPort方法設(shè)置webview推薦使用的窗口。setLoadWithOverviewMode方法是設(shè)置webview加載的頁面的模式。
ws.setSavePassword(true);
ws.setSaveFormData(true);// 保存表單數(shù)據(jù)
ws.setJavaScriptEnabled(true);
ws.setDomStorageEnabled(true);
my_web.setSaveEnabled(false);
ws.setSaveFormData(false);
// 下面的一句話是必須的,必須要打開javaScript不然所做一切都是徒勞的
ws.setJavaScriptEnabled(true);
ws.setSupportZoom(false);
xwebchromeclient = new xWebChromeClient();
//setWebChromeClient主要處理解析,渲染網(wǎng)頁等瀏覽器做的事情
//這個(gè)方法必須有,就算類中沒有函數(shù)也可以,不然視頻播放不了
my_web.setWebChromeClient(xwebchromeclient);
//WebChromeClient是輔助WebView處理Javascript的對(duì)話框,網(wǎng)站圖標(biāo),網(wǎng)站title,加載進(jìn)度等
my_web.setWebViewClient(new xWebViewClientent());
}
/**
 * 處理Javascript的對(duì)話框、網(wǎng)站圖標(biāo)、網(wǎng)站標(biāo)題以及網(wǎng)頁加載進(jìn)度等
 * @author
 */
public class xWebChromeClient extends WebChromeClient {
}

/**
 * 設(shè)置監(jiān)聽事件
 * 處理各種通知、請(qǐng)求等事件
 * @author
 */
 public class JsObject {
Context mContext;

JsObject(Context c) {
mContext = c;
}

   @JavascriptInterface
   public void log(){
   System.out.println("返回結(jié)果");
   setFullScreen();
   }
}
/**
 * 設(shè)置全屏
 */
private void setFullScreen() {
Log.i("視頻全屏-->", "豎屏切換到橫屏");
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
// 設(shè)置全屏的相關(guān)屬性,獲取當(dāng)前的屏幕狀態(tài),然后設(shè)置全屏
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);

// 全屏下的狀態(tài)碼:1098974464
// 窗口下的狀態(tài)嗎: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));

/*//點(diǎn)擊鏈接時(shí):
view.setWebViewClient(new WebViewClient(){
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {

view.loadUrl(url); //在當(dāng)前的webview中跳轉(zhuǎn)到新的url
System.out.println("鏈接--》"+url);
return true;
}
});
啟動(dòng)手機(jī)瀏覽器來打開新的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("返回結(jié)果");
setFullScreen();
}

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



}
/**
 * 設(shè)置全屏
 */
private void setFullScreen() {
Log.i("視頻全屏-->", "豎屏切換到橫屏");
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
// 設(shè)置全屏的相關(guān)屬性,獲取當(dāng)前的屏幕狀態(tài),然后設(shè)置全屏
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);

}


}

}

BrowserJsInject.class

package a0.android5.wevview2;

/**
 * Created by 趙理想on 2016/9/8.
 * 個(gè)人郵箱:1782980833@qq.com
 * *所屬公司:長江期貨
 * 該類用途:
 */

public class BrowserJsInject {

/**
 * Js注入
 * @param url 加載的網(wǎng)頁地址
 * @return 注入的js內(nèi)容,若不是需要適配的網(wǎng)址則返回空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:";
}
}

/**
 * 對(duì)不同的視頻網(wǎng)站分析相應(yīng)的全屏控件
 * @param url 加載的網(wǎng)頁地址
 * @return 相應(yīng)網(wǎng)站全屏按鈕的class標(biāo)識(shí)
 */
public static String referParser(String url){
if (url.contains("letv")) {
return "hv_ico_screen";   //樂視Tv
}else if (url.contains("youku")) {
return "x-zoomin";//優(yōu)酷
}else if (url.contains("bilibili")) {
return "icon-widescreen"; //bilibili
}else if (url.contains("qq")) {
return "tvp_fullscreen_button";   //騰訊視頻
}

return null;
}
}

特別提醒:
1.別忘記屏幕旋轉(zhuǎn)會(huì)影響聲明周期,可以參考我的另一篇文章http://www.itdecent.cn/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");下面。

哈哈,終于成功了??!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 179,063評(píng)論 25 709
  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 15,381評(píng)論 4 61
  • 電影《山河故人》中說:每個(gè)人只能陪你走一段路。我一直信以為真。 身邊要好的朋友從12歲升初中的時(shí)候開始隨某個(gè)階...
    愛笑猛獸閱讀 842評(píng)論 0 1
  • “你有過夢想成真嘛?” “有過吧” “什么啊” “她做了個(gè)夢說我們分手了,醒來就和我分手了” “摸摸頭,別難過” ...
    如果太陽足夠暖閱讀 276評(píng)論 1 0

友情鏈接更多精彩內(nèi)容