Android Webview基础

来源:互联网 发布:apache for mac下载 编辑:程序博客网 时间:2024/05/17 01:00

Hybrid App(混合模式移动应用)是指介于web-app、native-app这两者之间的app,兼具“Native App良好用户交互体验的优势”和“Web App跨平台开发的优势”,鉴于现在App应用需要对市场快速响应的需求,在Native中嵌入Webview的页面越来越被广泛的使用。本系列文章将从webview的基础,webview的原生接入,webview jsbridge(本系列打算介绍四种),webview安全,webview的优化五个维度来和大家一起对webview进行深入的剖析。
Android的SDK集成了WebView组件,也是View中的一种,它继承自AbsoluteLayout,展示网页的同时,也可以在其中放入其他的子View。从Android 4.4(KitKat)开始,原本基于WebKit的WebView开始基于Chromium内核,这一改动大大提升了WebView组件的性能以及对HTML5,CSS3,JavaScript的支持,同时修复了安全漏洞(Webview安全会详细讲解)。下面对Webview的基础知识进项详细介绍:
一、WebView加载:
(1)加载一个网页:
webView.loadUrl(“http://www.baidu.com/“);
(2)加载apk包中的一个html页面
webView.loadUrl(“file:///android_asset/my.html”);
此处有一个类似的场景:
当我们在WebView中加载出从web服务器上拿取的内容时,是无法访问本地资源的,如assets目录下的图片资源,因为这样的行为属于跨域行为(Cross-Domain),而WebView是禁止的。解决这个问题的方案是把html内容先下载到本地,然后用loadDataWithBaseURL加载html。这样就可以在html中使用 file:///android_asset/xxx.png 的链接来引用包里
面assets下的资源了。

private void loadWithAccessLocal(final String htmlUrl) {    //从网络上下载html的过程应放在工作线程中    new Thread(new Runnable() {        public void run() {            try {                final String htmlStr = NetService.getHtml(htmlUrl);                if (htmlStr != null) {                  //html下载成功后渲染出html的步骤应放在UI主线程,不然WebView会报错                    TaskExecutor.runTaskOnUiThread(new Runnable() {                        @Override                        public void run() {                            loadDataWithBaseURL(htmlUrl, htmlStr, "text/html", "UTF-8", "");                        }                    });                    return;                }            } catch (Exception e) {                Log.e("Exception:" + e.getMessage());            }            //html下载失败可以自定义错误界面            TaskExecutor.runTaskOnUiThread(new Runnable() {                @Override                public void run() {                    onPageLoadedError(-1, "html get failed");                }            });        }    }).start();}

(3)加载手机本地的一个html页面的方法:
webView.loadUrl(“content://com.android.html/sdcard/my.html”);
二、WebView基本组件:WebSettings、WebViewClient、WebChromeClient,它们的作用如下:
WebView: 主要负责解析和渲染网页
WebViewClient: 辅助WebView处理各种通知和请求事件
WebChromeClient: 用来辅助WebView处理Javascript的对话框,网站图标,网站title,加载进度等。
(1)WebSettings可以对WebView做如下设置:
这里写图片描述
(2)我们通过继承WebViewClient并重载它的方法可以实现不同功能的定制,如下所示(不贴图了,一页放不下):

private WebViewClient mWebViewClient = new WebViewClient(){        //在网页上的所有加载都经过这个方法,可以在此函数中做一些定制化的修改,比如获取url,查看url.equals(“xxx”)        @Override        public boolean shouldOverrideUrlLoading(WebView view, String url) {            //打开网页时不调用系统浏览器, 在本WebView中显示最新的url            view.loadUrl(url);            return true;        }        //重写此方法处理在浏览器中的按键事件。        @Override        public boolean shouldOverrideKeyEvent(WebView view, KeyEvent event) {            //个性化处理            return true;        }        //Key事件未被加载时调用        @Override        public void onUnhandledKeyEvent(WebView view, KeyEvent event) {            //个性化处理        }        //开始载入页面调用,可以设定一个loading的页面,告诉用户程序在等待网络响应。        @Override        public void onPageStarted(WebView view, String url, Bitmap favicon) {            //个性化处理        }        //在页面加载结束时调用,我们可以配合上面效果关闭loading条,切换程序动作。        @Override        public void onPageFinished(WebView view, String url) {            //个性化处理        }        // 在加载页面资源时会调用,每一个资源(图片)的加载都会调用一次。        @Override        public void onLoadResource(WebView view, String url) {            //个性化处理        }        //错误信息报告        @Override        public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {            //个性化处理        }        //webview发生改变时调用        @Override        public void onScaleChanged(WebView view, float oldScale, float newScale) {            //个性化处理        }        //更新历史记录        @Override        public void doUpdateVisitedHistory(WebView view, String url, boolean isReload) {            //个性化处理        }        //应用程序重新请求        @Override        public void onFormResubmission(WebView view, Message dontResend, Message resend) {            //个性化处理        }        //重写此方法让Webview可以处理https请求        @Override        public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {            //个性化处理        }        //获取返回信息授权请求        @Override        public void onReceivedHttpAuthRequest(WebView view, HttpAuthHandler handler, String host, String realm) {            //个性化处理        }    };    //把自定义的mWebViewClient设置给mWebView    mWebView.setWebViewClient(mWebViewClient );

(3)通过继承WebChromeClient并重载它的方法也可以实现不同功能的定制,如下图所示:

WebChromeClient mWebChromeClient = new WebChromeClient() {        //获得网页的加载进度,显示在右上角的TextView控件中,例如右上角可以显示一个Loading        @Override        public void onProgressChanged(WebView view, int newProgress) {            if (newProgress < 100) {                //自定义            } else {                //自定义            }        }        //获取Web页中的title用来设置自己界面中的title,但当加载出错的时候,比如无网络,这时onReceiveTitle中获取的标题为 找不到该网页,        //因此建议当触发onReceiveError时,不要使用获取到的title        @Override        public void onReceivedTitle(WebView view, String title) {            //自定义        }        @Override        public void onReceivedIcon(WebView view, Bitmap icon) {            //自定义        }        @Override        public boolean onCreateWindow(WebView view, boolean isDialog, boolean isUserGesture, Message resultMsg) {            //自定义            return true;        }        @Override        public void onCloseWindow(WebView window) {        }        //alert弹出框        @Override        public boolean onJsAlert(WebView view, String url, String message, JsResult result) {            //自定义            return true;        }        //处理confirm弹出框        @Override        public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult                result) {            //自定义            return true;        }        //处理prompt弹出框        @Override        public boolean onJsConfirm(WebView view, String url, String message, JsResult result) {            //自定义            return true;        }    };    //把自定义的mWebChromeClient设置给mWebView    mWebView.setWebChromeClient(mWebChromeClient);

三、WebView页面导航
(1)页面跳转:在WebView点击链接时, 默认的WebView会直接跳转到别的浏览器中, 如果想要实现在WebView内跳转就需要设置WebViewClient。如下所示:

mWebView.setWebViewClient(new WebViewClient(){      @Override      public boolean shouldOverrideUrlLoading(WebView view, String url) {          view.loadUrl(url);          //返回true: Android 系统会处理URL, 一般是唤起系统浏览器。          //返回false: 当前 WebView 处理URL。          return true;      }  });

(2)页面回退和前进:点击系统返回键同时判断webview是否可以回退,进行不同的逻辑处理

@Overridepublic boolean onKeyDown(int keyCode, KeyEvent event) {    if ((keyCode == KeyEvent.KEYCODE_BACK) && myWebView.canGoBack()) {        myWebView.goBack();        return true;    }else{        ...    }    return super.onKeyDown(keyCode, event);}

其他相关方法:

goBack ()  //后退goForward ()//前进//以当前的index为起始点前进或者后退到历史记录中指定的steps,如果steps为负数则为后退,正数则为前进goBackOrForward (int steps)canGoForward ()  //是否可以前进canGoBack () //是否可以后退

(3)页面滑动:关于页面滑动, 我们在做下拉刷新等功能时, 经常会去判断WebView是否滚动到顶部或者滚动到底部。请关注一下如下方法:

getScrollY() //方法返回的是当前可见区域的顶端距整个页面顶端的距离,也就是当前内容滚动的距离.getHeight()或者getBottom() //方法都返回当前WebView 这个容器的高度getContentHeight() 返回的是整个html 的高度,但并不等同于当前整个页面的高度,因为WebView 有缩放功能, 所以当前整个页面的高度实际上应该是原始html 的高度再乘上缩放比例. 因此,更正后的结果,准确的判断方法应该是:if (webView.getContentHeight() * webView.getScale() == (webView.getHeight() + webView.getScrollY())) {        //已经处于底端    }    if(webView.getScrollY() == 0){        //处于顶端    }

四、WebView的状态

onResume ()  //激活WebView为活跃状态,能正常执行网页的响应onPause ()  //当页面被失去焦点被切换到后台不可见状态,需要执行onPause动过, onPause动作通知内核暂停所有的动作,比如DOM的解析、plugin的执行、JavaScript执行。pauseTimers () //当应用程序被切换到后台我们使用了webview, 这个方法不仅仅针对当前的webview而是全局的全应用程序的webview,它会暂停所有webview的layout,parsing,javascripttimer。降低CPU功耗。resumeTimers ()  //恢复pauseTimers时的动作。destroy () //销毁,关闭了Activity时,音乐或视频,还在播放。就必须销毁。

但是注意:
webview调用destory时,webview仍绑定在Activity上.这是由于自定义webview构建时传入了该Activity的context对象,因此需要先从父容器中移除webview,然后再销毁webview。

  rootLayout.removeView(webView);    webView.destroy();

五、WebView Cache && Cookie:在项目中如果使用到WebView控件, 当加载html页面时, 会在/data/data/包名目录下生成database与cache两个文件夹。请求的url记录是保存在WebViewCache.db, 而url的内容是保存在WebViewCache文件夹下。
(1)控制缓存行为,如下:

WebSettings webSettings = mWebView.getSettings();//优先使用缓存webSettings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK); //只在缓存中读取webSettings.setCacheMode(WebSettings.LOAD_CACHE_ONLY);/不使用缓存WwebSettings.setCacheMode(WebSettings.LOAD_NO_CACHE);

清除缓存操作如下:

clearCache(true); //清除网页访问留下的缓存,由于内核缓存是全局的因此这个方法不仅仅针对webview而是针对整个应用程序.clearHistory (); //清除当前webview访问的历史记录,只会webview访问历史记录里的所有记录除了当前访问记录.clearFormData () //这个api仅仅清除自动完成填充的表单数据,并不会清除WebView存储到本地的数据。

(2)添加Cookie:

if (!DevUtil.hasLOLLIPOP()) {      CookieSyncManager.createInstance(mContext);   }CookieManager cookieManager = CookieManager.getInstance();cookieManager.setAcceptCookie(true);List<String> cookies = getCookies(customCookies);//项目中所使用到的所有cookie,因项目而异for (String cookie : cookies) {    cookieManager.setCookie(uri.getHost(), cookie);}if (DevUtil.hasLOLLIPOP()) {     cookieManager.flush(); } else {     CookieSyncManager.getInstance().sync(); }

清除cookie:

CookieManager.getInstance().removeSessionCookie();
1 0