欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android WebView基础应用详解

程序员文章站 2022-06-23 11:13:39
目录一、webview的基础配置二、webview支持播放音乐三、webview支持视频播放四、webchromeclient五、webviewclient1、重定向问题2、实现预加载3、增加错误页面...

附github源码:webviewexplore

一、webview的基础配置

websettings ws = getsettings();
ws.setbuiltinzoomcontrols(true);// 隐藏缩放按钮
ws.setlayoutalgorithm(websettings.layoutalgorithm.normal);// 排版适应屏幕
 
ws.setusewideviewport(true);// 可任意比例缩放
ws.setloadwithoverviewmode(true);// setusewideviewport方法设置webview推荐使用的窗口。setloadwithoverviewmode方法是设置webview加载的页面的模式。
 
ws.setsaveformdata(true);// 保存表单数据
ws.setjavascriptenabled(true); // 是否能与js交互【如果业务中无js交互,建议将此项关闭】
ws.setgeolocationenabled(true);// 启用地理定位【如果业务中无此业务,建议将此项关闭】
ws.setdomstorageenabled(true);
ws.setjavascriptcanopenwindowsautomatically(true);//允许js alert对话框等打开【如果业务中无此业务,建议将此项关闭】
ws.setsupportmultiplewindows(true);// 新加

二、webview支持播放音乐

//是否支持播放音乐
ws.setpluginstate(websettings.pluginstate.on);
ws.setmixedcontentmode(websettings.mixed_content_always_allow);
 
//是否需要用户点击才播放
ws.setmediaplaybackrequiresusergesture(true);

三、webview支持视频播放

android webview播放视频(包括全屏播放)

四、webchromeclient

/**
 * webchromeclient是辅助webview处理javascript的对话框,网站图标,网站title,加载进度等
*/
setwebchromeclient(new xwebchromeclient());

其具体覆盖方法如下: 

    public static class xwebchromeclient extends webchromeclient {
 
        /**
         * 获取网页加载进度
         * @param view
         * @param newprogress
         */
        @override
        public void onprogresschanged(webview view, int newprogress) {
            super.onprogresschanged(view, newprogress);
            log.d(tag, "onprogresschanged---> newprogress:" + newprogress);
        }
 
        /**
         * 获取网站标题 (android 6.0 以下通过title获取【捕捉http error】)
         *
         * @param view
         * @param title
         */
        @override
        public void onreceivedtitle(webview view, string title) {
            super.onreceivedtitle(view, title);
            log.d(tag, "onreceivedtitle---> title:" + title);
            if (webtitlecallback != null) {
                webtitlecallback.onreceived(title);
            }
            if (build.version.sdk_int < build.version_codes.m) {
                if (title.contains("404") || title.contains("500") || title.contains("error")) {
                    view.loadurl("about:blank"); // 避免出现默认的错误界面
                    // 在这里可以考虑显示自定义错误页
                    // showerrorpage();
                }
            }
        }
 
        /**
         * 网站图标
         *
         * @param view
         * @param icon
         */
        @override
        public void onreceivedicon(webview view, bitmap icon) {
            super.onreceivedicon(view, icon);
            log.d(tag, "icon:" + icon);
        }
 
        /**
         * 拦截alert弹框
         *
         * @param view
         * @param url
         * @param message
         * @param result
         * @return
         */
        @override
        public boolean onjsalert(webview view, string url, string message, jsresult result) {
            log.d(tag, "onjsalert");
            return super.onjsalert(view, url, message, result);
        }
 
        /**
         * 拦截 confirm弹框
         *
         * @param view
         * @param url
         * @param message
         * @param result
         * @return
         */
        @override
        public boolean onjsconfirm(webview view, string url, string message, jsresult result) {
            log.d(tag, "onjsconfirm");
            return super.onjsconfirm(view, url, message, result);
        }
 
        /**
         * 打印console信息
         *
         * @param consolemessage
         * @return
         */
        @override
        public boolean onconsolemessage(consolemessage consolemessage) {
            log.d(tag, "onconsolemessage");
            return super.onconsolemessage(consolemessage);
        }
 
        /**
         * 该方法在web页面请求某个尚未被允许或拒绝的权限时回调
         *
         * @param request
         */
        @override
        public void onpermissionrequest(permissionrequest request) {
            super.onpermissionrequest(request);
            log.d(tag, "onpermissionrequest---> request:" + request);
        }
    }

五、webviewclient

/**
 * webviewclient就是帮助webview处理各种通知、请求事件的
 */
setwebviewclient(new xwebviewclient());

其具体覆盖方法如下: 

    public class xwebviewclient extends webviewclient {
 
        @override
        public void onpagestarted(webview view, string url, bitmap favicon) {
            super.onpagestarted(view, url, favicon);
            log.d(tag, "onpagestarted---> url:" + url);
        }
 
        @override
        public void onpagefinished(webview view, string url) {
            super.onpagefinished(view, url);
            log.d(tag, "onpagefinished---> url:" + url);
        }
 
        /**
         * web页面加载错误时回调,这些错误通常都是由无法与服务器正常连接引起的。
         *
         * @param view
         * @param errorcode
         * @param description
         * @param failingurl
         */
        //android6.0之前的方法 【在新版本中也可能被调用,所以加上一个判断,防止重复显示】
        @override
        public void onreceivederror(webview view, int errorcode, string description, string failingurl) {
            super.onreceivederror(view, errorcode, description, failingurl);
            if (build.version.sdk_int < build.version_codes.m) {
                // 断网或者网络连接超时
                showreceivederrorpage(view, errorcode, description, failingurl);
            }
        }
 
        /**
         * 当服务器返回错误码时回调
         *
         * @param view
         * @param request
         * @param errorresponse
         */
        //6.0新增方法
        @requiresapi(api = build.version_codes.m)
        @override
        public void onreceivedhttperror(webview view, webresourcerequest request, webresourceresponse errorresponse) {
            super.onreceivedhttperror(view, request, errorresponse);
            // 这个方法在6.0才出现
            if (build.version.sdk_int >= build.version_codes.m) {
                int statuscode = 0;
                if (errorresponse != null) {
                    statuscode = errorresponse.getstatuscode();
                }
                log.d(tag, "onreceivedhttperror---> code = " + statuscode);
                if (404 == statuscode || 500 == statuscode) {
                    view.loadurl("about:blank");// 避免出现默认的错误界面
                    // 在这里可以考虑显示自定义错误页
                    // showerrorpage();
                }
            }
        }
    }

还有如下方法,在使用时尤其要注意:

1、重定向问题

在 shouldoverrideurlloading 方法可进行重定向的判断跟处理:

        /**
         * 重定向分析:
         *
         * @param view
         * @param request
         * @return true: 表示当前url已经加载完成,即使url还会重定向都不会再进行加载
         * false: 表示此url默认由系统处理,该重定向还是重定向,直到加载完成
         */
        //android7.0之后的方法
        @requiresapi(api = build.version_codes.n)
        @override
        public boolean shouldoverrideurlloading(webview view, webresourcerequest request) {
            log.d(tag, "shouldoverrideurlloading new---> url:" + request.geturl());
 
            analysisrequest(request);
 
            string url = (request.geturl()).tostring();
            boolean hasgesture = request.hasgesture();
            boolean isredirect = request.isredirect();
 
            return shouldoverride(view, url);
        }

其webview重定向需要考虑的case如下:

1、是最普通的http url【不含.doc .apk等下载url】

2、下载的http url【如.doc .apk等】

3、非http或https自定义url 【如 "weixin:// alipays://等】

【deprecated】如果期望打开web页时不自动唤起app,可通过 request.hasgesture()【是否】点击来判断,如果是true才唤起第三方app。(此种方案有时不太准确,故可采用下面方案)

【recommend】定义一个boolean值如:isclickweb = false,在ontouchevent down方法中,将其赋值为true。在必要位置添加判断即可【具体可参考代码】

        /**
         * 自定义重定向处理方法
         * @param view
         * @param url
         * @return
         */
        private boolean shouldoverride(webview view, final string url) {
            //业务需要可做处理
            redirectionjudge(view, url);
 
            if (schemeutil.ishttpprotocol(url) && !schemeutil.isdownloadfile(url)) {
                return false;
            }
 
            if (schemeutil.ishttpprotocol(url) && schemeutil.isdownloadfile(url)) {
                if (isclickweb) {
                    opendialog(url);
                    return true;
                }
            }
 
            if (!schemeutil.ishttpprotocol(url)) {
                boolean isvalid = schemeutil.isschemevalid(context, url);
                if (isvalid && isclickweb) {
                    opendialog(url);
                } else {
                    log.d(tag, "此scheme无效[比如手机中未安装该app]");
                }
                return true;
            }
            return false;
        }

2、实现预加载

在 shouldinterceptrequest 方法中可实现资源预加载:

        /**
         * 【实现预加载】
         * 有时候一个页面资源比较多,图片,css,js比较多,还引用了jquery这种庞然巨兽,
         * 从加载到页面渲染完成需要比较长的时间,有一个解决方案是将这些资源打包进apk里面,
         * 然后当页面加载这些资源的时候让它从本地获取,这样可以提升加载速度也能减少服务器压力。
         */
        @nullable
        @override
        public webresourceresponse shouldinterceptrequest(webview view, webresourcerequest request) {
            if (request == null) {
                return null;
            }
            string url = request.geturl().tostring();
            log.d(tag, "shouldinterceptrequest---> " + url);
            return getwebresourceresponse(url);
        }
        protected webresourceresponse getwebresourceresponse(string url) {
            //此处[tag]等需要跟服务端协商好,再处理
            if (url.contains("[tag]")) {
                try {
                    string localpath = url.replacefirst("^http.*[tag]\\]", "");
                    inputstream is = getcontext().getassets().open(localpath);
                    log.d(tag, "shouldinterceptrequest: localpath " + localpath);
                    string mimetype = "text/javascript";
                    if (localpath.endswith("css")) {
                        mimetype = "text/css";
                    }
                    return new webresourceresponse(mimetype, "utf-8", is);
                } catch (ioexception e) {
                    e.printstacktrace();
                    return null;
                }
            } else {
                return null;
            }
        }

3、增加错误页面展示限制

在onreceivederror方法中,通过 request.isformainframe() || url.equals(geturl() 判断来尽可能少的减少错误页面的展示。即当错误页面是主页面时才展示错误页,避免整个页面中如某个icon等展示错误,导致影响整个页面的情况【如网易音乐的某些url,就曾有出现这种情况,通过这种方式可以避免错误页面展示】。

        /**
         * 此方法中加载错误页面的时候,需要判断下 isformainframe 是否为true 亦或者 当前url跟加载的url是否为同一个url。
         *
         * @param view
         * @param request
         * @param error
         */
        //android6.0之后的方法
        @requiresapi(api = build.version_codes.m)
        @override
        public void onreceivederror(webview view, webresourcerequest request, webresourceerror error) {
            super.onreceivederror(view, request, error);
            if (build.version.sdk_int >= build.version_codes.m) {
                string url = request.geturl().tostring();
                int errorcode = error.geterrorcode();
                string description = error.getdescription().tostring();
                log.d(tag, "onreceivederror---> " + " url:" + url + "errorcode:" + errorcode + " description:" + description + " failingurl:" + url + " request.isformainframe():" + request.isformainframe());
                // 如果当前网络请求是为main frame创建的,则显示错误页
                if (request.isformainframe() || url.equals(geturl())) {
                    showreceivederrorpage(view, error.geterrorcode(), error.getdescription().tostring(), request.geturl().tostring());
                }
            }
        }

4、解决页面白屏问题

当ssl证书无效时,会导致白屏问题,可在 onreceivedsslerror 方法中添加 handler.proceed();

可解决白屏问题: 

        /**
         * 【解决白屏问题】
         * 如ssl证书无效时调用
         *
         * @param view
         * @param handler
         * @param error
         */
        @override
        public void onreceivedsslerror(webview view, sslerrorhandler handler, sslerror error) {
            //此处处理可避免ssl证书无效的页面白屏
            handler.proceed();
            super.onreceivedsslerror(view, handler, error);
            log.d(tag, "onreceivedsslerror---> error = " + error);
        }

以上就是android webview基础应用详解的详细内容,更多关于android webview的资料请关注其它相关文章!