关于webview的使用详解

使用步骤

加载url

webview.loadUrl(“一个url/一个文件的路径”)

webview的配置和管理,利用webSettings

具体的代码如下:

//声明WebSettings子类
WebSettings webSettings = webView.getSettings();

//如果访问的页面中要与Javascript交互,则webview必须设置支持Javascript
webSettings.setJavaScriptEnabled(true);  
//特别注意,在android开发中一定要合理的利用资源
// 若加载的 html 里有JS 在执行动画等操作,会造成资源浪费(CPU、电量)
// 在 onStop 和 onResume 里分别把 setJavaScriptEnabled() 给设置成 false 和 true 即可
//支持插件
webSettings.setPluginsEnabled(true); 
//设置自适应屏幕,两者合用
webSettings.setUseWideViewPort(true); //将图片调整到适合webview的大小 
webSettings.setLoadWithOverviewMode(true); // 缩放至屏幕的大小

//缩放操作
webSettings.setSupportZoom(true); //支持缩放,默认为true。是下面那个的前提。
webSettings.setBuiltInZoomControls(true); //设置内置的缩放控件。若为false,则该WebView不可缩放
webSettings.setDisplayZoomControls(false); //隐藏原生的缩放控件

//其他细节操作
webSettings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK); //关闭webview中缓存 
webSettings.setAllowFileAccess(true); //设置可以访问文件 
webSettings.setJavaScriptCanOpenWindowsAutomatically(true); //支持通过JS打开新窗口 
webSettings.setLoadsImagesAutomatically(true); //支持自动加载图片
webSettings.setDefaultTextEncodingName("utf-8");//设置编码格式

//特别注意
//webview在安卓5.0之前默认允许其加载混合网络协议内容,在安卓5.0之后,默认不允许加载http与https混合内容,需要设置webview允许其加载混合网络协议内容
mWebView.getSettings().setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);

关于webview的缓存是需要重点说一说的了,每次面试到这里是必问的。
当我们加载html的时候,都会在date/date/包名目录下生成database 与 cache 两个文件夹。
请求的 URL记录保存在 WebViewCache.db,而 URL的内容是保存在 WebViewCache 文件夹下
我们可以根据我们的需要来灵活设置setCacheMode

//优先使用缓存: 
    WebView.getSettings().setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK); 
        //缓存模式如下:
        //LOAD_CACHE_ONLY: 不使用网络,只读取本地缓存数据
        //LOAD_DEFAULT: (默认)根据cache-control决定是否从网络上取数据。
        //LOAD_NO_CACHE: 不使用缓存,只从网络获取数据.
        //LOAD_CACHE_ELSE_NETWORK,只要本地有,无论是否过期,或者no-cache,都使用缓存中的数据。

另外我们也可以动态的指定我们的缓存路径和缓存空间大小
webSettings.setAppCachePath(cacheDirPath); //设置 Application Caches 缓存目录
WebSettings.setAppCacheMaxSize()//设置缓存的最大空间
注意,每个 Application 只调用一次

webViewClient的使用

作用是处理各种通知,比如加载页面时候各个状态的回调等等。
在webViewClient中有很多重写的方法,我们可以根据需要在这些方法中做我们需要的设置操作。举几个常用的方法。
- shouldOverrideUrlLoading():打开网页时不调用系统浏览器, 而是在本WebView中显示。
- onPageStarted():开始载入页面调用的,我们可以设定一个loading的页面,告诉用户程序在等待网络响应。
- onPageFinished():页面加载结束时候调用的,可以配合onPageStarted()使用,结束loading。
- onLoadResource():加载页面资源的时候调用,比如图片等,每一个资源的加载都会调用一次。这个需要了解,但是偶尔也会用到,比如我们需要对资源的加载特殊处理呢
- onReceivedError():加载页面失败,服务器出现错误的情况。这个方法就比较常用了,我们的app设计都要求美观人性化的,如果这里加载出错了还想浏览器那样404是不是很丑呢,所以在这种情况下我们会加载本地的一个错误页面来显示,获取还会有交互。
- onReceivedSslError():如果你的应用安全性较强,并且使用了https协议,那么就会用到这个方法。因为webview默认是不处理https请求的,需要在这个方法中进行设置。

 WebChromeClient的使用

作用是辅助webview处理js,以及网页的logo和title等。和WebViewClient一样,也有很多回调方法,也说常用的
- onProgressChanged():加载网页的时候回调,返回当前的加载进度,一般用来显示进度条
- onReceivedTitle():获取网页的标题。这个是常用的,我们在加载web的时候,标题可能是我们自己的控件,所以就要在这个回调中获取当前页面的title并显示。

 其他方法
//是否可以后退,返回值boolean
Webview.canGoBack() 
//后退网页
Webview.goBack()

//是否可以前进,返回值boolean                   
Webview.canGoForward()
//前进网页
Webview.goForward()

//以当前的index为起始点前进或者后退到历史记录中指定的steps
//如果steps为负数则为后退,正数则为前进
Webview.goBackOrForward(intsteps) 

//清除网页访问留下的缓存
//由于内核缓存是全局的因此这个方法不仅仅针对webview而是针对整个应用程序.
Webview.clearCache(true);

//清除当前webview访问的历史记录
//只会webview访问历史记录里的所有记录除了当前访问记录
Webview.clearHistory();

//这个api仅仅清除自动完成填充的表单数据,并不会清除WebView存储到本地的数据
Webview.clearFormData();

android和js的交互

以上我们可以根据需求灵活的加载我们的h5页面,随着h5页面的广泛使用,那么和android的交互就是必不可少的。交互主要分两种方式:

  1. android调用js
    a、webview.loadUrl(“javascript:callJS()”)
    javascript:固定写法;callJS():js方法名
    因为是通过loadUrl()的形式,所以调用的时候会引起页面刷新
    b、mWebView.evaluateJavascript(”javascript:callJS()”, new ValueCallback() {
    @Override
    public void onReceiveValue(String value) {
    //此处为 js 返回的结果
    }
    });
    }

此方式相对于loadUrl()效率高,不会引起界面的刷新。另外还有一个直观的优点,就是处理返回值比较容易。缺点是只能适配4.4以上版本。所以在开发中我们需要对版本进行判断,两者结合使用,灵活开发。
2. js调用android
a、通过shouldOverrideUrlLoading ()回调拦截 url
拦截到url解析这个地址,监测到我们预先设定好的字段,就调用我们的方法。如果需要参数也是从地址中检测取出的。这种方式最简单,好操作也好理解。
b、通过 WebView的addJavascriptInterface()进行对象映射
mWebView.addJavascriptInterface(new AndroidtoJs(), “login“);//AndroidtoJS
参数一是js对象名,里边是供js调用的方法
@JavascriptInterface
public void androidtoJSTest(String msg) {
ToastUtil.show(msg);
}
参数二是java对象名,和js之间的一个约束,两边必须统一
比如js代码 :
function callAndroid(){
// 由于对象映射,所以调用login对象等于调用Android映射的对象
window.login.androidtoJSTest(“js调用了android中的androidtoJSTest方法”);
}
注意粗体和斜体的地方是一一对应的,名字必须统一。

webview所存在的安全隐患

addJavascriptInterface引起的代码任意执行漏洞:
分析漏洞产生的原因:

通过addJavascriptInterface接口进行对象映射来实现js调用android方法。通过对象映射,那么当js拿到这个对象后,是不是就可以对这个对象中的方法任意调用,包括系统类,从而进行代码的任意执行。比如说访问手机中存储的数据从而泄漏一些个人信息。

攻击的核心代码:
function execute(cmdArgs)  
{  
    // 步骤1:遍历 window 对象
    // 目的是为了找到包含 getClass ()的对象
    // 因为Android映射的JS对象也在window中,所以肯定会遍历到
    for (var obj in window) {  
        if ("getClass" in window[obj]) {  

      // 步骤2:利用反射调用forName()得到Runtime类对象
            alert(obj);          
            return  window[obj].getClass().forName("java.lang.Runtime")  

      // 步骤3:以后,就可以调用静态方法来执行一些命令,比如访问文件的命令
getMethod("getRuntime",null).invoke(null,null).exec(cmdArgs);  

// 从执行命令后返回的输入流中得到字符串,有很严重暴露隐私的危险。
// 如执行完访问文件的命令之后,就可以得到文件名的信息了。
        }  
    }  
}
解决方案

谷歌规定>=4.2的版本,被调用的函数通过@JavascriptInterface的注解来避免漏洞攻击。
那么<4.2的版本该如何解决呢,分析上边的原因知道,是因为js拿到了java对象,直接调用android的方法造成的安全隐患。那么我们只要不让其直接调用,是不是就可以解决了。找一个桥梁,做一个嫁接。
让js调用本地一js代码,该方法通过调用prompt()将js中的信息传递到android端。而在android端onJsPrompt()中解析传递过来的数据,再进行java对象方法的调用。这样一来,js就没有机会攻击我们的代码了。

信息明文存储的隐患:
产生的原因:

所谓明文存储是指在交互的过程中可能会存在让用户输入密码的情况。一旦设置mWebView.setSavePassword(true),在用户输入的时候会提示用户是否保存密码,一旦选择是就会将信息明文保存在webview.db中。那么就会有被窃取的风险。

解决方案:

mWebView.setSavePassword(false),将密码保存提醒关闭

WebView中getSettings类的方法对 WebView 安全性的影响:
1、setAllowFileAccess()
// 设置是否允许 WebView 使用 File 协议
webView.getSettings().setAllowFileAccess(true);     
// 默认设置为true,即允许在 File 域下执行任意 JavaScript 代码

使用 file 域加载的 js代码能够使用进行同源策略跨域访问,从而导致隐私信息泄露
解决方案:
对于不需要使用file协议的应用,将其禁止。对于需要使用file协议的应用,禁止file协议加载js

2、.setAllowFileAccessFromFileURLs()
// 设置是否允许通过 file url 加载的 Js代码读取其他的本地文件
webView.getSettings().setAllowFileAccessFromFileURLs(true);
// 在Android 4.1前默认允许
// 在Android 4.1后默认禁止

如果将其设置为true,攻击者的js就可以读取到我们的本地文件,所以这里建议设置为false

3、setAllowUniversalAccessFromFileURLs()
// 设置是否允许通过 file url 加载的 Javascript 可以访问其他的源(包括http、https等源)
webView.getSettings().setAllowUniversalAccessFromFileURLs(true);

// 在Android 4.1前默认允许(setAllowFileAccessFromFileURLs()不起作用)
// 在Android 4.1后默认禁止

所以这个也建议设置为false

4、setJavaScriptEnabled()
// 设置是否允许 WebView 使用 JavaScript(默认是不允许)
webView.getSettings().setJavaScriptEnabled(true);  

// 但很多应用(包括移动浏览器)为了让 WebView 执行 http 协议中的 JavaScript,都会主动设置为true,不区别对待是非常危险的

如果是file协议,禁用 javascript 可以很大程度上减小跨源漏洞对 WebView 的威胁。但是并不能完全杜绝。

总结:
安全隐患是webview存在的一大问题,根据以上情况的分析,结合自己的需求,选择合适的解决方案。


老生常谈的内存泄漏

在android开发中,资源的合理利用和分配是至关重要的。这里就主要说说webview使用不当引起的内存泄漏问题:

产生原因:

当我们在xml中静态创建webview,并且在包含该webview的activity的onDestroy()中调用webview.destroy()方法和webview=null;来回收内存,但是我们发现并没有任何效果。

解决方案:

代码中动态创建webview,添加到合适的位置。在ondestroy()方法中先后执行

mWebView.loadUrl(null);
mWebView.clearHistory();
((ViewGroup) mWebView.getParent()).removeView(mWebView);
mWebView.destroy();
mWebView = null;

注意:
动态创建webview的时候要传入ApplicationContext,如果传入activity的context的话,对内存的引用会一直持有着。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值