WebView缓存简述

Posted by alonealice on 2017-12-19

WebView缓存在日常的使用中非常重要,它不仅能使用户能够在离线的情况下依旧可以使用它,更重要的是,它可以加快网页的加载速度,减少服务器的负载。

WebView主要包括两类缓存,一类是浏览器自带的网页数据缓存,这是所有的浏览器都支持的、由HTTP协议定义的缓存;另一类是H5缓存,这是由web页面的开发者设置的。

浏览器自带的网页数据缓存

浏览器缓存机制是通过HTTP协议Header里的Cache-Control(或Expires)和Last-Modified(或 Etag)等字段来控制文件缓存的机制。下面具体来讲讲这几个字段的意义:

Cache-Control:max-age=60,这表示缓存时长为60秒。如果60秒内需要再次请求这个文件,那么浏览器不会发出请求,直接使用本地的缓存的文件。这是HTTP/1.1标准中的字段。

**Expires: Thu, 31 Dec 2017 23:55:55 GMT,**这表示这个文件的过期时间是2017年12月31日晚上23点55分55秒,在这个时间之前浏览器都不会再次发出请求去获取这个文件。这是HTTP/1.0中的字段,如果客户端和服务器时间不同步会导致缓存出现问题。

当它们同时出现在HTTP Response的Header中时,Cache-Control优先级更高。

**Last-Modified:Wed, 28 Sep 2016 09:24:35 GMT,**这表示这个文件最后的修改时间是2016年9月28日9点24分35秒。这个字段对于浏览器来说,会在下次请求的时候,作为Request Header的If-Modified-Since字段带上。例如浏览器缓存的文件已经超过了Cache-Control(或者Expires),那么需要加载这个文件时,就会发出请求,请求的Header有一个字段为If-Modified-Since:Wed, 28 Sep 2016 09:24:35 GMT,服务器接收到请求后,会把文件的Last-Modified时间和这个时间对比,如果时间没变,那么浏览器将返回304 Not Modified给浏览器,让浏览器继续使用缓存。如果时间有变化,那么服务器会返回200 OK,并返回相应的内容给浏览器。

**ETag:”57eb8c5c-129”,**这是文件的特征串。功能同上面的Last-Modified是一样的。只是在浏览器下次请求时,ETag是作为Request Header中的If-None-Match:"57eb8c5c-129"字段传到服务器。服务器和最新的文件特征串对比,如果相同那么返回304 Not Modified,不同则返回200 OK。当ETag和Last-Modified同时出现时,任何一个字段只要生效了,就认为文件是没有更新的。

WebView要支持这些属性,需要对WebSetting做相应的设置。

1
2
WebSettings settings = webView.getSettings();
settings.setCacheMode(WebSettings.LOAD_DEFAULT);

WebView总共有下面几个Cache Mode:

  • LOAD_CACHE_ONLY: 不使用网络,只读取本地缓存数据。
  • LOAD_DEFAULT: 根据cache-control决定是否从网络上取数据。
  • LOAD_CACHE_NORMAL: API level 17中已经废弃,从API level 11开始作用同LOAD_DEFAULT模式
  • LOAD_NO_CACHE: 不使用缓存,只从网络获取数据。
  • LOAD_CACHE_ELSE_NETWORK,只要本地有,无论是否过期,或者no-cache,都使用缓存中的数据。本地没有缓存时才从网络上获取。

H5的缓存

到目前为止,H5 一共有6种缓存机制,有些是之前已有,有些是 H5 才新加入的。
浏览器缓存机制:Dom Storgage(Web Storage)存储机制,Web SQL Database 存储机制,Application Cache(AppCache)机制,Indexed Database (IndexedDB),File System API。

下面我们就依次来讲讲这些缓存机制以及WebView要支持这些机制时需要做哪些。

Dom Storage 存储机制

DOM 存储是一套在 Web Applications 1.0 规范中首次引入的与存储相关的特性的总称,现在已经分离出来,单独发展成为独立的 W3C Web 存储规范。 DOM 存储被设计为用来提供一个更大存储量、更安全、更便捷的存储方法,从而可以代替掉将一些不需要让服务器知道的信息存储到 cookies 里的这种传统方法。

Dom Storage 是通过存储字符串的 Key/Value 对来提供的,并提供 5MB(不同浏览器可能不同,分 HOST)的存储空间。

DOM Storage 分为 sessionStorage 和 localStorage。localStorage 对象和 sessionStorage 对象使用方法基本相同,它们的区别在于作用的范围不同。sessionStorage 用来存储与页面相关的数据,它在页面关闭后无法使用。而 localStorage 则持久存在,在页面关闭后也可以使用。

localStorage 是个全局对象,它维护着在页面会话(page session)期间有效的存储空间。只要浏览器开着,页面会话周期就会一直持续。当页面重新载入(reload)或者被恢复(restores)时,页面会话也是一直存在的。每在新标签或者新窗口中打开一个新页面,都会初始化一个新的会话。

LocalStorage 是全局性的,同时打开两个页面会共享一份存数据,在一个页面中修改数据,另一个页面中是可以感知到的。

总体上来说,Dom Storage 给 Web 提供了一种更录活的数据存储方式,存储空间更大(相对 Cookies),用法也比较简单,方便存储服务器或本地的一些临时数据,但是它只适合存储比较简单的数据,如果要存储对象,需要将其转为json数据。

WebView中如果需要使用Dom Storage,那么就需要在WebSetting中将其的开关打开。

1
webView.getSettings().setDomStorageEnabled(true);
Web SQL Database存储机制

Web SQL Database是H5 提供的基于 SQL 的数据库存储机制,用于存储适合数据库的结构化数据。根据官方的标准文档,Web SQL Database 存储机制不再推荐使用,将来也不再维护,而是推荐使用 AppCache 和 IndexedDB。

SQL Database 的主要优势在于能够存储结构复杂的数据,能充分利用数据库的优势,可方便对数据进行增加、删除、修改、查询。由于 SQL 语法的复杂性,使用起来麻烦一些。SQL Database 也不太适合做静态文件的缓存。

在 Android 内嵌 Webview 中,需要通过 Webview 设置接口启用 SQL Database,同时还要设置数据库文件的存储路径。

1
2
webView.getSettings().setDatabaseEnabled(true);
webView.getSettings().setDatabasePath(path);
Application Cache 机制

Application Cache(简称 AppCache类似于浏览器的缓存(Cache-Control 和 Last-Modified)机制,都是以文件为单位进行缓存,且文件有一定更新机制。但 AppCache 是对浏览器缓存机制的补充,不是替代。

要使用 AppCache,需要在HTML 在头中通过 manifest 属性引用 manifest 文件。在manifest 文件中列出了缓存文件CACHE MANIFEST,网络文件NETWORK以及错误文件FALLBACK。

总的来说,浏览器在首次加载 HTML 文件时,会解析 manifest 属性,并读取 manifest 文件,获取 Section:CACHE MANIFEST 下要缓存的文件列表,再对文件缓存。

在使用AppCache也会有一些问题:

1.要更新缓存的文件,需要更新包含它的 manifest 文件,那怕只加一个空格。常用的方法,是修改 manifest 文件注释中的版本号。如:# 2012-02-21 v1.0.0
2.被缓存的文件,浏览器是先使用,再通过检查 manifest 文件是否有更新来更新缓存文件。这样缓存文件可能用的不是最新的版本。
3.在更新缓存过程中,如果有一个文件更新失败,则整个更新会失败。
4.manifest 和引用它的HTML要在相同 HOST。
5.manifest 文件中的文件列表,如果是相对路径,则是相对 manifest 文件的相对路径。
6.manifest 也有可能更新出错,导致缓存文件更新失败。
7.没有缓存的资源在已经缓存的 HTML 中不能加载,即使有网络。
8.manifest 文件本身不能被缓存,且 manifest 文件的更新使用的是浏览器缓存机制。所以 manifest 文件的 Cache-Control 缓存时间不能设置太长。

另外,根据官方文档,AppCache 已经不推荐使用了,Webview要使用AppCache,需要设置接口启用 AppCache,同时还要设置缓存文件的存储路径,另外还可以设置缓存的空间大小。

1
2
webSettings.setAppCacheEnabled(true);
webSettings.setAppCachePath(cachePath); webSettings.setAppCacheMaxSize(5*1024*1024);

Indexed Database

IndexedDB 也是一种数据库的存储机制,但不同于已经不再支持的 Web SQL Database。IndexedDB 不是传统的关系数据库,可归为 NoSQL 数据库。IndexedDB 又类似于 Dom Storage 的 key-value 的存储方式,但功能更强大,且存储空间更大。

IndexedDB 存储数据是 key-value 的形式。Key 是必需,且要唯一;Key 可以自己定义,也可由系统自动生成。Value 也是必需的,但 Value 非常灵活,可以是任何类型的对象。一般 Value 都是通过 Key 来存取的。

Android 在4.4开始加入对 IndexedDB 的支持,只需打开允许 JS 执行的开关就好了。

1
webSettings.setJavaScriptEnabled(true);

File System API

File System API 是 H5 新加入的存储机制。它为 Web App 提供了一个虚拟的文件系统,就像 Native App 访问本地文件系统一样。由于安全性的考虑,这个虚拟文件系统有一定的限制。Web App 在虚拟的文件系统中,可以进行文件(夹)的创建、读、写、删除、遍历等操作。
File System API 也是一种可选的缓存机制,和前面的 SQLDatabase、IndexedDB 和 AppCache 等一样。File System API 有自己的一些特定的优势:1.可以满足大块的二进制数据( large binary blobs)存储需求;2.可以通过预加载资源文件来提高性能;3.可以直接编辑文件。

到目前,Android 系统的 Webview 还不支持 File System API。

参考资料

WebView缓存原理分析和应用

H5 缓存机制浅析 移动端 Web 加载性能优化