WebView渲染引擎
- Android4.4之前基于WebKit,详情:WebKit;
- Android4.4之后基于Chromium;
WebView关键类
- WebView:加载网页的容器,包含了网页加载的常用方法,如:加载、前进、后退等;
- WebSettings:对WebView进行配置和管理,如:配置缓存、控制缩放等;
- WebViewClient:帮助WebView处理各种回调、通知和请求事件;
- WebChromeClient辅助WebView处理JavaScript的对话框、图标、Title、加载进度等信息;
JS和Android的交互方法
对于Android调用JS代码的方法有2种
- 通过WebView的loadUrl();直接加载“javascript:方法”;
- 通过WebView的evaluateJavascript();4.4以上才能使用,不会使页面刷新,容易获取JS返回的结果;
JS调用Android代码的方法有3种
- 通过WebView的addJavascriptInterface()进行对象映射;4.2以下注意安全问题,4.2以上要在添加@JavascriptInterface注解;
- 通过WebViewClient的shouldOverrideUrlLoading()方法回调拦截url;需要事先约定协议,解析url;缺点是JS获取Android方法的返回值复杂;
- 通过WeChromeClient的onJsAlert()、onJsConfirm()、onJsPrompt方法回调拦截JS对话框alert()、confirm()、prompt()消息;需要事先约定协议;
交互的安全漏洞
WebView任意代码执行漏洞
原因
- WebView中的addJavascriptInterface()接口(4.2之前);
- WebView内置导出的searchBoxJavaBridge_对象;
- WebView内置导出的accessibility和accessibilityTraversal对象;
风险
解决方法
- 4.2以上,在方法上增加@JavascriptInterface注解;
- 4.2以下,注入一段本地JS代码来约束JS端的方法调用;核心:将本地JSCall对象中的所有方法都以字符串的形式写入JS代码中,JS中方法调用返回JSON字符串,本地解析JSON字符串反射调用相应方法;注意:需要过滤掉Object类的方法;
- 删除内置导出的对象
域控制不严格漏洞
WebView的缓存机制
浏览器页面缓存
原理
根据 HTTP 协议头里的 Cache-Control(或 Expires)和 Last-Modified(或 Etag)等字段来控制文件缓存的机制;
WebView端控制
缓存目录
- Android4.3:/data/data/package name/cache/webviewCacheChromium
- Android5.0:/data/data/package name/app_webview/Cache
- Android6.0:/data/data/package name/cache
Application Cache
注意:高版本中 setAppCachePath 方法不会生效;
Android4.3中的缓存目录位置:
Dom Storage缓存机制
原理
Dom Storage 是通过存储字符串的 Key/Value 对来提供的,并提供 5MB (不同浏览器可能不同,分 HOST)的存储空间(Cookies 才 4KB)。另外 Dom Storage 存储的数据在本地,不像 Cookies,每次请求一次页面,Cookies 都会发送给服务器。 DOM Storage 分为 sessionStorage 和 localStorage。localStorage 对象和 sessionStorage 对象使用方法基本相同,它们的区别在于作用的范围不同。sessionStorage 用来存储与页面相关的数据,它在页面关闭后无法使用。而 localStorage 则持久存在,在页面关闭后也可以使用。
开启方法
缓存目录
Android6.0:
Android5.0:
Web SQL Database缓存机制
原理
H5 也提供基于 SQL 的数据库存储机制,用于存储适合数据库的结构化数据。根据官方的标准文档,Web SQL Database 存储机制不再推荐使用,将来也不再维护,而是推荐使用 AppCache 和 IndexedDB。
开启方法
Indexed Database机制
原理
IndexedDB 也是一种数据库的存储机制,但不同于已经不再支持的 Web SQL Database。IndexedDB 不是传统的关系数据库,可归为 NoSQL 数据库。IndexedDB 又类似于 Dom Storage 的 key-value 的存储方式,但功能更强大,且存储空间更大。
开发方法
File System API
原理
File System API 是 H5 新加入的存储机制。它为 Web App 提供了一个虚拟的文件系统,就像 Native App 访问本地文件系统一样。由于安全性的考虑,这个虚拟文件系统有一定的限制。Web App 在虚拟的文件系统中,可以进行文件(夹)的创建、读、写、删除、遍历等操作。 File System API 也是一种可选的缓存机制,和前面的 SQLDatabase、IndexedDB 和 AppCache 等一样。File System API 有自己的一些特定的优势:
- 可以满足大块的二进制数据( large binary blobs)存储需求。
- 可以通过预加载资源文件来提高性能。
- 可以直接编辑文件。
注意:到目前,Android 系统的 Webview 还不支持 File System API。
部分缓存文件的存储格式
以Android4.3中的文件为例:DB文件
各种缓存机制的比较
WebView内存泄露问题
- 尽量不要在xml中定义webview节点,而是动态生成;
- 在onDestroy方法中执行:
public void destroy() {
if (mWebView != null) {
// 如果先调用destroy()方法,则会命中if (isDestroyed()) return;这一行代码,需要先onDetachedFromWindow(),再
// destory()
ViewParent parent = mWebView.getParent();
if (parent != null) {
((ViewGroup) parent).removeView(mWebView);
}
mWebView.stopLoading();
// 退出时调用此方法,移除绑定的服务,否则某些特定系统会报错
mWebView.getSettings().setJavaScriptEnabled(false);
mWebView.clearHistory();
mWebView.clearView();
mWebView.removeAllViews();
try {
mWebView.destroy();
} catch (Throwable ex) {
}
}
}
复制代码
- 在单独进程中加载WebView,使用完后直接kill进程;
WebView的重定向问题
常见错误写法
shouldOverrideUrlLoading 方法中调用view.loadUrl方法;
解决方法
应该去掉view.loadUrl(url)调用;
注意事项
主动调用webview.load(url)的话不会触发shouldOverrideUrlLoading方法;
其他处理重定向方案
- WebView有一个getHitTestResult():返回的是一个HitTestResult,一般会根据打开的链接的类型,返回一个extra的信息,如果打开链接不是一个url,或者打开的链接是JavaScript的url,他的类型是UNKNOWN_TYPE,这个url就会通过requestFocusNodeHref(Message)异步重定向。返回的extra为null,或者没有返回extra。根据此方法的返回值,判断是否为null,可以用于解决网页重定向。
- 自定义回退栈。
参考资料
- https://www.kancloud.cn/digest/android-safe/107906
- https://my.oschina.net/zhibuji/blog/100580
- https://juejin.im/entry/5977598d51882548c0045bde