WebView使用詳解、H5網(wǎng)頁(yè)視頻全屏播放 、網(wǎng)頁(yè)跳轉(zhuǎn)空白

image.png

內(nèi)容:介紹webview的使用方法,介紹WebViewClient、WebChromeClient,H5網(wǎng)頁(yè)視頻全屏播放,網(wǎng)頁(yè)跳轉(zhuǎn)空白問(wèn)題
最近做項(xiàng)目老愛(ài)和H5打交道,遇到了很多問(wèn)題也踩了許多坑,今天在這兒總結(jié)下,方便后人乘涼。
關(guān)于安卓和H5交互可參考我之前的文章:原生與H5交互介紹
WebView基礎(chǔ)設(shè)置

private void initWebView() {
        mWebView.setWebViewClient(new MyWebViewClient());       //設(shè)置在WebView中打開鏈接,不設(shè)置則調(diào)用自帶瀏覽器。主要針對(duì)View進(jìn)行攔截處理
        mWebView.setWebChromeClient(new MyWebChromeClient());

        WebSettings webSettings = mWebView.getSettings();
        webSettings.setJavaScriptEnabled(true);     //支持JS
        webSettings.setDomStorageEnabled(true);       //啟用dom內(nèi)存,防止js加載失敗
        webSettings.setAllowFileAccess(true);       //允許訪問(wèn)文件
        webSettings.setSupportZoom(true);       //支持縮放
        webSettings.setLoadWithOverviewMode(true);      //是否啟動(dòng)概述模式瀏覽界面,當(dāng)頁(yè)面寬度超過(guò)WebView顯示寬度時(shí),縮小頁(yè)面適應(yīng)WebView。默認(rèn)false
        webSettings.setGeolocationEnabled(false);       //是否允許定位
        webSettings.setLoadsImagesAutomatically(true);      //是否加載圖片
//      webSettings.setCacheMode(WebSettings.LOAD_DEFAULT);     //設(shè)置緩存模式
//      webSettings.setDefaultTextEncodingName("UTF-8");        //設(shè)置頁(yè)面的編碼格式,默認(rèn)UTF-8
    }

WebViewClient主要是對(duì)view一系列操作進(jìn)行監(jiān)聽攔截。包括:網(wǎng)頁(yè)加載開始、網(wǎng)頁(yè)加載完成、錯(cuò)誤攔截處理。(代碼中注釋會(huì)詳解,再次不多做介紹)
WebChromeClient主要是對(duì)瀏覽器進(jìn)行監(jiān)聽。例如彈窗、是否顯示支持全屏播放等。(代碼中注釋會(huì)詳解,再次不多做介紹)
網(wǎng)頁(yè)加載空白問(wèn)題,我只在7.0及以上遇到,貌似是說(shuō)證書錯(cuò)誤,可能越往上安全性越高吧,按照下面處理下就行了

/**
         * HTTPS通信的網(wǎng)址(以https://開頭的網(wǎng)站)出現(xiàn)錯(cuò)誤時(shí)
         * 證書錯(cuò)誤攔截處理
         * 安卓7.0需要
         */
        @Override
        public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
            if(error.getPrimaryError() == android.net.http.SslError.SSL_INVALID ){// 校驗(yàn)過(guò)程遇到了bug
                handler.proceed();      //忽略錯(cuò)誤繼續(xù)加載
            }else{
                handler.cancel();       //取消加載
            }
        }

視頻全屏播放:安卓不像IOS一樣可以直接全屏播放,需要在WebChromeClient對(duì)其進(jìn)行設(shè)置,相當(dāng)于是new 一個(gè)Fragment讓其來(lái)進(jìn)行全屏播放

    /*** 視頻播放相關(guān)的方法 **/
        @Override
        public View getVideoLoadingProgressView() {
            FrameLayout frameLayout = new FrameLayout(MainActivity.this);
            frameLayout.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
            return frameLayout;
        }

        @Override
        public void onShowCustomView(View view, CustomViewCallback callback) {
            showCustomView(view, callback);
        }

        @Override
        public void onHideCustomView() {
            hideCustomView();
        }
image.png

代碼如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <Button
        android:id="@+id/btn_load"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="LOAD"/>

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <WebView
            android:id="@+id/web_view"
            android:layout_width="match_parent"
            android:layout_height="match_parent">
        </WebView>

        <ProgressBar
            android:id="@+id/pb_loading"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:visibility="gone"/>
    </RelativeLayout>

</LinearLayout>
public class MainActivity extends AppCompatActivity {

    @BindView(R.id.btn_load)
    Button mBtnLoad;
    @BindView(R.id.web_view)
    WebView mWebView;
    @BindView(R.id.pb_loading)
    ProgressBar mPbLoading;

    /** 視頻全屏參數(shù) */
    protected static final FrameLayout.LayoutParams COVER_SCREEN_PARAMS = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
    private View customView;
    private FrameLayout fullscreenContainer;
    private WebChromeClient.CustomViewCallback customViewCallback;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ButterKnife.bind(this);
        initWebView();
    }

    private void initWebView() {
        mWebView.setWebViewClient(new MyWebViewClient());       //設(shè)置在WebView中打開鏈接,不設(shè)置則調(diào)用自帶瀏覽器。主要針對(duì)View進(jìn)行攔截處理
        mWebView.setWebChromeClient(new MyWebChromeClient());

        WebSettings webSettings = mWebView.getSettings();
        webSettings.setJavaScriptEnabled(true);     //支持JS
        webSettings.setDomStorageEnabled(true);       //啟用dom內(nèi)存,防止js加載失敗
        webSettings.setAllowFileAccess(true);       //允許訪問(wèn)文件
        webSettings.setSupportZoom(true);       //支持縮放
        webSettings.setLoadWithOverviewMode(true);      //是否啟動(dòng)概述模式瀏覽界面,當(dāng)頁(yè)面寬度超過(guò)WebView顯示寬度時(shí),縮小頁(yè)面適應(yīng)WebView。默認(rèn)false
        webSettings.setGeolocationEnabled(false);       //是否允許定位
        webSettings.setLoadsImagesAutomatically(true);      //是否加載圖片
//      webSettings.setCacheMode(WebSettings.LOAD_DEFAULT);     //設(shè)置緩存模式
//      webSettings.setDefaultTextEncodingName("UTF-8");        //設(shè)置頁(yè)面的編碼格式,默認(rèn)UTF-8
    }

    @OnClick(R.id.btn_load)
    public void onViewClicked() {
        mWebView.loadUrl("http://www.baidu.com");
    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {

        if (keyCode == KeyEvent.KEYCODE_BACK) {
            //優(yōu)先退出全屏播放
            if (customView != null) {
                hideCustomView();
                return true;
            } else {
                if (mWebView.canGoBack()) {
                    mWebView.goBack();      //返回上個(gè)頁(yè)面
                    return true;
                } else {
                    System.exit(0);     //退出程序
                }
            }
        }
        return super.onKeyDown(keyCode, event);
    }


    /**
     * 針對(duì)網(wǎng)頁(yè)進(jìn)行攔截處理
     */
    public class MyWebViewClient extends WebViewClient{

        /**
         *可以實(shí)現(xiàn)對(duì)網(wǎng)頁(yè)中超鏈接的攔截
         */
        @Override
        public boolean shouldOverrideUrlLoading(WebView view, String url) {

            //例:攔截電話網(wǎng)址,直接調(diào)用本地電話
            if (url.contains("tel:")){
                startActivity(new Intent(Intent.ACTION_DIAL, Uri.parse(url)));
                return true;
            }

            if (url.startsWith("http:") || url.startsWith("https:")) {
                view.loadUrl(url);
                return true;
            }
        /*  WebView.HitTestResult hitTestResult = view.getHitTestResult();
            //hitTestResult==null解決重定向問(wèn)題
            if (!TextUtils.isEmpty(url) && hitTestResult == null) {
                view.loadUrl(url);
                return true;
            }*/

            return super.shouldOverrideUrlLoading(view, url);
        }

        /**
         *開始加載
         */
        @Override
        public void onPageStarted(WebView view, String url, Bitmap favicon) {
            super.onPageStarted(view, url, favicon);
            mPbLoading.setVisibility(View.VISIBLE);
        }

        /**
         * 結(jié)束加載
         */
        @Override
        public void onPageFinished(WebView view, String url) {
            super.onPageFinished(view, url);
            mPbLoading.setVisibility(View.GONE);
        }

        /**
         * 加載錯(cuò)誤的時(shí)候會(huì)產(chǎn)生這個(gè)回調(diào)
         */
        @Override
        public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
            super.onReceivedError(view, errorCode, description, failingUrl);
            //TODO
        }

        /**
         * HTTPS通信的網(wǎng)址(以https://開頭的網(wǎng)站)出現(xiàn)錯(cuò)誤時(shí)
         * 證書錯(cuò)誤攔截處理
         * 安卓7.0需要
         */
        @Override
        public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
            if(error.getPrimaryError() == android.net.http.SslError.SSL_INVALID ){// 校驗(yàn)過(guò)程遇到了bug
                handler.proceed();      //忽略錯(cuò)誤繼續(xù)加載
            }else{
                handler.cancel();       //取消加載
            }
        }
    }

    /**
     * 針對(duì)瀏覽器攔截處理
     */
    public class MyWebChromeClient extends WebChromeClient{

        /**
         * 彈窗攔截
         */
        @Override
        public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
            return super.onJsAlert(view, url, message, result);
        }

        /**
         * 彈窗攔截
         */
        @Override
        public boolean onJsConfirm(WebView view, String url, String message, JsResult result) {
            return super.onJsConfirm(view, url, message, result);
        }

        /**
         * 彈窗攔截
         */
        @Override
        public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) {
            return super.onJsPrompt(view, url, message, defaultValue, result);
        }

        /**
         * 加載進(jìn)度攔截
         */
        @Override
        public void onProgressChanged(WebView view, int newProgress) {
            super.onProgressChanged(view, newProgress);
        }

        /**
         * 文件選擇
         */
        @Override
        public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, FileChooserParams fileChooserParams) {
            selectImage();
            return super.onShowFileChooser(webView, filePathCallback, fileChooserParams);
        }

        /*** 視頻播放相關(guān)的方法 **/
        @Override
        public View getVideoLoadingProgressView() {
            FrameLayout frameLayout = new FrameLayout(MainActivity.this);
            frameLayout.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
            return frameLayout;
        }

        @Override
        public void onShowCustomView(View view, CustomViewCallback callback) {
            showCustomView(view, callback);
        }

        @Override
        public void onHideCustomView() {
            hideCustomView();
        }
    }

    /**
     * 圖片選擇
     */
    private void selectImage() {
        //TODO
    }

    /**
     * 視頻播放全屏
     */
    private void showCustomView(View view, WebChromeClient.CustomViewCallback callback) {

        // if a view already exists then immediately terminate the new one
        if (customView != null) {
            callback.onCustomViewHidden();
            return;
        }
        getWindow().getDecorView();

        //獲取虛擬按鍵高度,防止遮擋
        if(ScreenUtils.hasNavBar(this)){
            COVER_SCREEN_PARAMS.setMargins(0,0,0,ScreenUtils.getNavigationBarHeight(this));
        }

        FrameLayout decor = (FrameLayout) getWindow().getDecorView();
        fullscreenContainer = new FullscreenHolder(this);
        fullscreenContainer.addView(view, COVER_SCREEN_PARAMS);
        decor.addView(fullscreenContainer, COVER_SCREEN_PARAMS);
        customView = view;
        setStatusBarVisibility(false);
        customViewCallback = callback;
    }

    /**
     * 隱藏視頻全屏
     */
    private void hideCustomView() {
        if (customView == null) {
            return;
        }
        setStatusBarVisibility(true);
        FrameLayout decor = (FrameLayout) getWindow().getDecorView();
        decor.removeView(fullscreenContainer);
        fullscreenContainer = null;
        customView = null;
        customViewCallback.onCustomViewHidden();
        mWebView.setVisibility(View.VISIBLE);
    }

    /**
     * 全屏容器界面
     */
    static class FullscreenHolder extends FrameLayout {

        public FullscreenHolder(Context ctx) {
            super(ctx);
            setBackgroundColor(ctx.getResources().getColor(android.R.color.black));
        }

        @Override
        public boolean onTouchEvent(MotionEvent evt) {
            return true;
        }
    }

    private void setStatusBarVisibility(boolean visible) {
        int flag = visible ? 0 : WindowManager.LayoutParams.FLAG_FULLSCREEN;
        getWindow().setFlags(flag, WindowManager.LayoutParams.FLAG_FULLSCREEN);
    }
}

贈(zèng)人玫瑰,手有余香。您的支持是我創(chuàng)作最大的動(dòng)力!

最后編輯于
?著作權(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),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

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