
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);
    }
}
赠人玫瑰,手有余香。您的支持是我创作最大的动力!