WebView使用详解、H5网页视频全屏播放 、网页跳转空白

image.png

内容:介绍webview的使用方法,介绍WebViewClient、WebChromeClient,H5网页视频全屏播放,网页跳转空白问题
最近做项目老爱和H5打交道,遇到了很多问题也踩了许多坑,今天在这儿总结下,方便后人乘凉。
关于安卓和H5交互可参考我之前的文章:原生与H5交互介绍
WebView基础设置

private void initWebView() {
        mWebView.setWebViewClient(new MyWebViewClient());       //设置在WebView中打开链接,不设置则调用自带浏览器。主要针对View进行拦截处理
        mWebView.setWebChromeClient(new MyWebChromeClient());

        WebSettings webSettings = mWebView.getSettings();
        webSettings.setJavaScriptEnabled(true);     //支持JS
        webSettings.setDomStorageEnabled(true);       //启用dom内存,防止js加载失败
        webSettings.setAllowFileAccess(true);       //允许访问文件
        webSettings.setSupportZoom(true);       //支持缩放
        webSettings.setLoadWithOverviewMode(true);      //是否启动概述模式浏览界面,当页面宽度超过WebView显示宽度时,缩小页面适应WebView。默认false
        webSettings.setGeolocationEnabled(false);       //是否允许定位
        webSettings.setLoadsImagesAutomatically(true);      //是否加载图片
//      webSettings.setCacheMode(WebSettings.LOAD_DEFAULT);     //设置缓存模式
//      webSettings.setDefaultTextEncodingName("UTF-8");        //设置页面的编码格式,默认UTF-8
    }

WebViewClient主要是对view一系列操作进行监听拦截。包括:网页加载开始、网页加载完成、错误拦截处理。(代码中注释会详解,再次不多做介绍)
WebChromeClient主要是对浏览器进行监听。例如弹窗、是否显示支持全屏播放等。(代码中注释会详解,再次不多做介绍)
网页加载空白问题,我只在7.0及以上遇到,貌似是说证书错误,可能越往上安全性越高吧,按照下面处理下就行了

/**
         * HTTPS通信的网址(以https://开头的网站)出现错误时
         * 证书错误拦截处理
         * 安卓7.0需要
         */
        @Override
        public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
            if(error.getPrimaryError() == android.net.http.SslError.SSL_INVALID ){// 校验过程遇到了bug
                handler.proceed();      //忽略错误继续加载
            }else{
                handler.cancel();       //取消加载
            }
        }

视频全屏播放:安卓不像IOS一样可以直接全屏播放,需要在WebChromeClient对其进行设置,相当于是new 一个Fragment让其来进行全屏播放

    /*** 视频播放相关的方法 **/
        @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;

    /** 视频全屏参数 */
    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());       //设置在WebView中打开链接,不设置则调用自带浏览器。主要针对View进行拦截处理
        mWebView.setWebChromeClient(new MyWebChromeClient());

        WebSettings webSettings = mWebView.getSettings();
        webSettings.setJavaScriptEnabled(true);     //支持JS
        webSettings.setDomStorageEnabled(true);       //启用dom内存,防止js加载失败
        webSettings.setAllowFileAccess(true);       //允许访问文件
        webSettings.setSupportZoom(true);       //支持缩放
        webSettings.setLoadWithOverviewMode(true);      //是否启动概述模式浏览界面,当页面宽度超过WebView显示宽度时,缩小页面适应WebView。默认false
        webSettings.setGeolocationEnabled(false);       //是否允许定位
        webSettings.setLoadsImagesAutomatically(true);      //是否加载图片
//      webSettings.setCacheMode(WebSettings.LOAD_DEFAULT);     //设置缓存模式
//      webSettings.setDefaultTextEncodingName("UTF-8");        //设置页面的编码格式,默认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) {
            //优先退出全屏播放
            if (customView != null) {
                hideCustomView();
                return true;
            } else {
                if (mWebView.canGoBack()) {
                    mWebView.goBack();      //返回上个页面
                    return true;
                } else {
                    System.exit(0);     //退出程序
                }
            }
        }
        return super.onKeyDown(keyCode, event);
    }


    /**
     * 针对网页进行拦截处理
     */
    public class MyWebViewClient extends WebViewClient{

        /**
         *可以实现对网页中超链接的拦截
         */
        @Override
        public boolean shouldOverrideUrlLoading(WebView view, String url) {

            //例:拦截电话网址,直接调用本地电话
            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解决重定向问题
            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);
        }

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

        /**
         * 加载错误的时候会产生这个回调
         */
        @Override
        public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
            super.onReceivedError(view, errorCode, description, failingUrl);
            //TODO
        }

        /**
         * HTTPS通信的网址(以https://开头的网站)出现错误时
         * 证书错误拦截处理
         * 安卓7.0需要
         */
        @Override
        public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
            if(error.getPrimaryError() == android.net.http.SslError.SSL_INVALID ){// 校验过程遇到了bug
                handler.proceed();      //忽略错误继续加载
            }else{
                handler.cancel();       //取消加载
            }
        }
    }

    /**
     * 针对浏览器拦截处理
     */
    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);
        }

        /**
         * 加载进度拦截
         */
        @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);
        }

        /*** 视频播放相关的方法 **/
        @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);
    }
}

赠人玫瑰,手有余香。您的支持是我创作最大的动力!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容