H5里面的App Cache是由开发Web页面的开发者控制的,而不是由Native去控制的,但是Native里面的WebView也需要我们做一下设置才能支持H5的这个特性。
1.工作原理
写Web页面代码时,指定manifest属性即可让页面使用App Cache。通常html页面代码会这么写:
<html manifest="xxx.appcache">
</html>
xxx.appcache文件用的是相对路径,这时appcache文件的路径是和页面一样的。也可以使用的绝对路径,但是域名要保持和页面一致。
完整的xxx.appcache文件一般包括了3个section,基本格式如下:
CACHE MANIFEST
# 2017-05-13 v1.0.0
/bridge.js
NETWORK:
*
FALLBACK:
/404.html
- CACHE MANIFEST下面文件就是要被浏览器缓存的文件
- NETWORK下面的文件就是要被加载的文件
- FALLBACK下面的文件是目标页面加载失败时的显示的页面
AppCache工作的原理:当一个设置了manifest文件的html页面被加载时,CACHE MANIFEST指定的文件就会被缓存到浏览器的App Cache目录下面。当下次加载这个页面时,会首先应用通过manifest已经缓存过的文件,然后发起一个加载xxx.appcache文件的请求到服务器,如果xxx.appcache文件没有被修改过,那么服务器会返回304 Not Modified给到浏览器,如果xxx.appcache文件被修改过,那么服务器会返回200 OK,并返回新的xxx.appcache文件的内容给浏览器,浏览器收到之后,再把新的xxx.appcache文件中指定的内容加载过来进行缓存。
可以看到,AppCache缓存需要在每次加载页面时都发出一个xxx.appcache的请求去检查manifest文件是不是有更新(byte by byte)。根据这篇文章(H5 缓存机制浅析 移动端 Web 加载性能优化)的介绍,AppCache有一些坑的地方,且官方已经不推荐使用了,但目前主流的浏览器依然是支持的。文章里主要提到下面这些坑:
- 要更新缓存的文件,需要更新包含它的 manifest 文件,那怕只加一个空格。常用的方法,是修改 manifest 文件注释中的版本号。如:# 2012-02-21 v1.0.0
- 被缓存的文件,浏览器是先使用,再通过检查 manifest 文件是否有更新来更新缓存文件。这样缓存文件可能用的不是最新的版本。
- 在更新缓存过程中,如果有一个文件更新失败,则整个更新会失败。
- manifest 和引用它的HTML要在相同 HOST。
- manifest 文件中的文件列表,如果是相对路径,则是相对 manifest 文件的相对路径。
- manifest 也有可能更新出错,导致缓存文件更新失败。
- 没有缓存的资源在已经缓存的 HTML 中不能加载,即使有网络。例如:http://appcache-demo.s3-website-us-east-1.amazonaws.com/without-network/
- manifest 文件本身不能被缓存,且 manifest 文件的更新使用的是浏览器缓存机制。所以 manifest 文件的 Cache-Control 缓存时间不能设置太长。
2.WebView如何设置才能支持AppCache
WebView默认是没有开启AppCache支持的,需要添加下面这几行代码来设置:
WebSettings webSettings = webView.getSettings();
webSettings.setAppCacheEnabled(true);
String cachePath = getApplicationContext().getCacheDir().getPath(); // 把内部私有缓存目录'/data/data/包名/cache/'作为WebView的AppCache的存储路径
webSettings.setAppCachePath(cachePath);
webSettings.setAppCacheMaxSize(5 * 1024 * 1024);
注意:WebSettings的setAppCacheEnabled和setAppCachePath都必须要调用才行。
3.存储AppCache的路径
按照Android SDK的API说明,setAppCachePath是可以用来设置AppCache路径的,但是我实际测试发现,不管你怎么设置这个路径,设置到应用自己的内部私有目录还是外部SD卡,都无法生效。AppCache缓存文件最终都会存到/data/data/包名/app_webview/cache/Application Cache这个文件夹下面,在上面的Android 4.4和5.1系统目录截图可以看得到,但是如果你不调用setAppCachePath方法,WebView将不会产生这个目录。这里有点让我觉得奇怪,我猜测可能从某一个系统版本开始,为了缓存文件的完整性和安全性考虑,SDK实现的时候就吧AppCache缓存目录设置到了内部私有存储。