gta5删除“apppackage cache 删除”文件仍然无法打开

WebApp缓存管理:WebAppCache - 为程序员服务
WebApp缓存管理:WebAppCache
智能手机的发展
伴随着智能手机在国内的普及及其换代速度,HTML5技术在移动领域的发展终究比PC端来的更迅速些。
根据移动互联网第三方数据挖掘和整合营销机构艾媒咨询(iiMedia Research)发布的《2012中国智能手机市场年度研究报告》数据显示,截止2012Q4季度,中国智能手机用户数达到了3.8亿,同比增长72.7%;
2012中国智能手机用户规模发展状况
报告指出,在操作系统占有率方面,Android份额到达68.6%,iOS有所下滑,占12.8%,Symbian则难抑下滑趋势,占12.4%,Windows Phone作为后起之秀,份额只占3.8%,但后续占有率会持续扩大;
2012年中国智能手机市场操作系统分布状况
在系统平台分布方面,Android上V2.x是主流版本,iOS上V5是主流版本
2012年中国智能手机市场Android、iOS平台版本分布
(以上数据来自iiMedia Research《2012中国智能手机市场年度研究报告》)
Application Cache的问题
回到正题,HTML5伴随着智能手机的发展,在手机应用开发方面的优势越发凸显,尤其是其跨平台、版本更新等优势;在一些对性能要求稍低及项目人员紧张的产品中,使用WebApp的形式(大多为Native App+WebApp的混搭方式)不失为一种好的解决方案。
排除WIFI,对于国内那昂贵的流量费用,而且是极不稳定的GPRS来说,WebApp的开发不得不考虑一个问题:缓存。
开始我很兴奋,知道HTML5给我们提供了,通过manifest文件,我终于可以翱翔在离线数据的大海中。
理想很丰满,现实却总是很骨感;Application Cache这货可真不好管理,如果你还不清楚它的实际情况,可以参考下这篇文章,内容我就不翻译了,但标题我得翻译下:《Application Cache就是个人渣》。
关于Application Cache,有一个致命的缺点,那就是你不能选择更新哪些资源。你的manifest文件更新了,所有指定的资源都会给下载,对于流量是金的移动互联网来说,这不就是坑爹嘛。
localStorage
但上帝总在关了一扇门之后,给我们开启另一扇门,而这一扇门就是:localStorage。
localStorage的存储空间是按域名来计算的,不同平台容量不同,即使相同平台相同版本但由于手机厂商调教不一,造成实际使用中的大小也是不一样的。就拿笔者的MX2(Android 4.1)自带的浏览器来说,测试出来的结果是64M。虽然不同平台及版本存在差异,但对于大部分WebApp来说,这样的存储空间已经可以派上大用场了。
Android 2.3
(以上数据来自,测试地址点)
在使用localStorage前,我们还需要清楚webview对localStorage的影响,特别是对于那些嵌套在不同客户端的WebApp来说,webview对localStorage的支持与否也是不可忽视的一点。同时,对于业务较多的根域来说,不同WebApp之间可能会出现空间上的使用管理混乱问题,这需要在前期规划时对存储做好队列管理工作。
解决方案:WebAppCache
考虑到Application Cache的维护麻烦问题,在我最近的项目中就基本放弃了manifest的方式,转而使用类MVC的方式(估且这么叫吧)。
方案由app.json配置应用的每个资源信息,app.html进行整个应用的调度,包括版本对比、更新以及缓存队列管理。由于使用了Ajax来拉取文件,所以受同源访问限制,对跨域请求有要求的同学,可以使用,这里就不仔细展开了,只是提供其中一种简单的实现方式。
假设我们的目录结构如下:
|---app.manifest
|---app.html
|---WebAppCache.js
|---index.html
|---inner/
|---demo.html
|---zepto.min.js
|---touch.min.js
|---app.js
|---demo.js
|---global.css
|---inner/
|---demo.css
WebAppCache约定app.html与app.json处于相同的目录层级,其他的资源不作要求。
则实际请求地址如下:
index.html
-& /app/app.html 或 /app/app.html?v=index
inner/demo.html -& /app/app.html?v=inner.demo
app.json应用配置文件
// 配置app.json文件过期时间(分钟)
"expire": "30",
// 核心加载的js文件
"jsCore": ["zepto", "touch"],
// 核心加载的css文件
"cssCore": ["global"],
"jsConfig": {
// js基准路径
"path": "/app/js/",
// js缺省后缀
"suffix": ".js"
// css配置
"cssConfig": {
// css基准路径
"path": "/app/css/",
// css缺省后缀
"suffix": ".css"
// 页面配置
"pageConfig": {
// 页面基准路径
"path": "/app/page/",
// 页面缺省后缀
"suffix": ".html"
// 声明应用js资源
"zepto": {
// 指定拉取路径,url为空时以"基准路径+模块名+缺省后缀"拉取
"url": "/app/js/zepto.min.js",
// 版本号,-1时不作缓存
"v": "1.0.0"
"touch": {
"url": "/app/js/touch.min.js",
"v": "1.0.0"
"v": "1.0.0"
"v": "1.0.0"
// 声明应用css资源
"global": {
"url": "/app/css/global.css",
"v": "1.0.0"
"v": "1.0.1"
"inner.demo": {
"v": "1.0.0"
// 声明应用页面
"index": {
// 声明除去核心加载外需要加载的资源
"js": ["app"],
"css": ["app"]
"inner.demo": {
"js": ["app", "demo"],
"css": ["app", "inner.demo"]
app.html缓存调度
&!DOCTYPE html&
&html manifest="/app/app.manifest"&
&title&&/title&
&meta charset="utf-8"&
&script type="text/javascript" src="/app/WebAppCache.js"&&/script&
app.html我使用了Application Cache,这在不使用SPA方式对页面进行documwnt.write输出时,可以加快页面载入速度。当所有的资源处理完毕之后,会将内容渲染到当前页面输出。
WebAppCache.js之队列管理
为了兼容同一根域下多WebApp的场景,WebAppCache.js以应用为单位进行缓存管理,每次进行写操作时,都会缓存当前的key到队列里;同时资源队列以”资源缓存时间先后 + css核心资源(按依赖权重由低到高排列)+ js核心资源(按依赖权重由低到高排列)“进行排列;
在溢出时,按App使用时间先后进行队列淘汰;当所有非当前App淘汰完毕后,再对当前App资源进行资源队列淘汰;在淘汰当前App资源队列后仍无法存储时,最后尝试清空当前App缓存再试。
* 优化的缓存设置, 溢出捕获以及队列管理
function cache(n, v, prefix) {
prefix = (getType(prefix) == 'string') ? prefix : _appN
if (getType(v) == 'undefined') {
var r = _storage.getItem(prefix + n);
if (r === null) {
return JSON.parse(r);
} catch (e) {
// 缓存当前应用的写操作key值(无序)
if (prefix == _appName) {
var cacheKey = cache('CacheKey') || [];
cacheKey.push(n);
cacheKey = uniq(cacheKey);
_storage.setItem(_appName + 'CacheKey', JSON.stringify(cacheKey));
if (getType(v) != 'string') {
v = JSON.stringify(v);
_storage.setItem(prefix + n, v);
} catch (e) {
var appName = shiftAppCache();
if (appName !== false) { // 重新尝试缓存
cache(n, v);
} else { // 没有应用缓存可供删除时, 淘汰当前应用队列
var cq = cache('Core') || [],
sq = sourceQueue();
// 将Core与Source资源合并进行队列管理
sq = sq.concat(cq);
// 缓存区不足时,淘汰当前应用缓存重新发起请求
if (sq.length & 1) {
clearAppCache(_appName);
window.location.reload(false);
var item = sq.shift(),
key = _appName +
// 删除最早的缓存
_storage.removeItem(key);
_storage.removeItem(key + '.Version');
// 更新队列
sourceQueue(sq);
// 重新尝试缓存
cache(n, v);
* 清空应用缓存
function clearAppCache(appName) {
var cacheKey = cache('CacheKey', undefined, appName) || [];
each(cacheKey, function(k, v) {
_storage.removeItem(appName + v);
_storage.removeItem(appName + 'CacheKey');
* 按应用缓存队列清空应用缓存(跳过当前应用缓存)
function shiftAppCache() {
var appQueue = cache('App.Queue', undefined, '') || [];
appQueue = arrDel(_appName, appQueue); // 跳过当前应用缓存
if (appQueue.length & 0) {
var appName = appQueue.shift();
clearAppCache(appName);
cache('App.Queue', appQueue, '');
return appName
对于同一根域下多WebApp的场景,当用户同时开启多个应用造成空间不足时,当前的解决方案在localStorage支持的情况下可能会出现数据缓存不久就被淘汰的情况,这种情况可以通过转换为sessionStorage来进行优化。
有一点需要注意,在使用document.write输出文档流时,要在window.onload触发后方可进行页面渲染,否则原文档流不会被覆盖。
最后附上GitHub地址:
PS:感谢maple同学提供Banner~ ^_^
让生活支付更完美
原文地址:, 感谢原作者分享。
您可能感兴趣的代码当我们加载Html时候,会在我们data/应用package下生成database与cache两个文件夹:
我们请求的Url记录是保存在webviewCache.db里,而url的内容是保存在webviewCache文件夹下.
WebView中存在着两种缓存:网页数据缓存(存储打开过的页面及资源)、H5缓存(即AppCache)。
一、网页缓存
1、缓存构成
/data/data/package_name/cache/
/data/data/package_name/database/webview.db
/data/data/package_name/database/webviewCache.db
WebView缓存文件结构如下图所示
再看一下&webviewCache 数据库结构
综合可以得知 webview 会将我们浏览过的网页url已经网页文件(css、图片、js等)保存到数据库表中
缓存模式(5种)
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,都使用缓存中的数据。
如:的cache-control为no-cache,在模式LOAD_DEFAULT下,无论如何都会从网络上取数据,如果没有网络,就会出现错误页面;在LOAD_CACHE_ELSE_NETWORK模式下,无论是否有网络,只要本地有缓存,都使用缓存。本地没有缓存时才从网络上获取。
.cn的cache-control为max-age=60,在两种模式下都使用本地缓存数据。
总结:根据以上两种模式,建议缓存策略为,判断是否有网络,有的话,使用LOAD_DEFAULT,无网络时,使用LOAD_CACHE_ELSE_NETWORK。
设置WebView 缓存模式
view plaincopy
private&void&initWebView()&{&&&&&&&&&&&&&&&&&&&&mWebView.getSettings().setJavaScriptEnabled(true);&&&&&&&&&&mWebView.getSettings().setRenderPriority(RenderPriority.HIGH);&&&&&&&&&&mWebView.getSettings().setCacheMode(WebSettings.LOAD_DEFAULT);&&//设置&缓存模式&&&&&&&&&&//&开启&DOM&storage&API&功能&&&&&&&&&&mWebView.getSettings().setDomStorageEnabled(true);&&&&&&&&&&//开启&database&storage&API&功能&&&&&&&&&&mWebView.getSettings().setDatabaseEnabled(true);&&&&&&&&&&&String&cacheDirPath&=&getFilesDir().getAbsolutePath()+APP_CACAHE_DIRNAME;&&//&&&&&&String&cacheDirPath&=&getCacheDir().getAbsolutePath()+Constant.APP_DB_DIRNAME;&&&&&&&&&&Log.i(TAG,&&cacheDirPath=&+cacheDirPath);&&&&&&&&&&//设置数据库缓存路径&&&&&&&&&&mWebView.getSettings().setDatabasePath(cacheDirPath);&&&&&&&&&&//设置&&Application&Caches&缓存目录&&&&&&&&&&mWebView.getSettings().setAppCachePath(cacheDirPath);&&&&&&&&&&//开启&Application&Caches&功能&&&&&&&&&&mWebView.getSettings().setAppCacheEnabled(true);&&&&&&}&&
view plaincopy
/**&&&&&&*&清除WebView缓存&&&&&&*/&&&&&&public&void&clearWebViewCache(){&&&&&&&&&&&&&&&&&&&&//清理Webview缓存数据库&&&&&&&&&&try&{&&&&&&&&&&&&&&deleteDatabase(&webview.db&);&&&&&&&&&&&&&&&deleteDatabase(&webviewCache.db&);&&&&&&&&&&}&catch&(Exception&e)&{&&&&&&&&&&&&&&e.printStackTrace();&&&&&&&&&&}&&&&&&&&&&&&&&&&&&&&//WebView&缓存文件&&&&&&&&&&File&appCacheDir&=&new&File(getFilesDir().getAbsolutePath()+APP_CACAHE_DIRNAME);&&&&&&&&&&Log.e(TAG,&&appCacheDir&path=&+appCacheDir.getAbsolutePath());&&&&&&&&&&&&&&&&&&&&File&webviewCacheDir&=&new&File(getCacheDir().getAbsolutePath()+&/webviewCache&);&&&&&&&&&&Log.e(TAG,&&webviewCacheDir&path=&+webviewCacheDir.getAbsolutePath());&&&&&&&&&&&&&&&&&&&&//删除webview&缓存目录&&&&&&&&&&if(webviewCacheDir.exists()){&&&&&&&&&&&&&&deleteFile(webviewCacheDir);&&&&&&&&&&}&&&&&&&&&&//删除webview&缓存&缓存目录&&&&&&&&&&if(appCacheDir.exists()){&&&&&&&&&&&&&&deleteFile(appCacheDir);&&&&&&&&&&}&&&&&&}&&
view plaincopy
package&com.example.&&&&import&java.io.F&&&&import&android.app.A&&import&android.graphics.B&&import&android.os.B&&import&android.util.L&&import&android.view.V&&import&android.webkit.JsPromptR&&import&android.webkit.JsR&&import&android.webkit.WebChromeC&&import&android.webkit.WebS&&import&android.webkit.WebSettings.RenderP&&import&android.webkit.WebV&&import&android.webkit.WebViewC&&import&android.widget.RelativeL&&import&android.widget.TextV&&import&android.widget.T&&&&public&class&MainActivity&extends&Activity&{&&&&&&&&private&static&final&String&TAG&=&MainActivity.class.getSimpleName();&&&&&&private&static&final&String&APP_CACAHE_DIRNAME&=&&/webcache&;&&&&&&private&TextView&tv_topbar_&&&&&&private&RelativeLayout&rl_&&&&&&private&WebView&mWebV&&&&&&private&String&&&&&&&&&@Override&&&&&&protected&void&onCreate(Bundle&savedInstanceState)&{&&&&&&&&&&super.onCreate(savedInstanceState);&&&&&&&&&&setContentView(R.layout.activity_main);&&&&&&&&&&&&&&&&&&&&//url:/detail/31ccbc9eaa794df686cbc?apikey=jFaWGVHdFVhekZYWTBWV1ZHSkZOVlJWY&app=com.yulore.yellowsdk_ios&uid=627&&&&&&&&&&url&=&&/detail/31ccbc9eaa794df686cbc?apikey=jFaWGVHdFVhekZYWTBWV1ZHSkZOVlJWY&app=com.yulore.yellowsdk_ios&uid=627&;&&&&&&&&&&findView();&&&&&&}&&&&&&&&private&void&findView()&{&&&&&&&&&&&&&&&&&&&&tv_topbar_title&=&(TextView)&findViewById(R.id.tv_topbar_title);&&&&&&&&&&&&&&&&&&&&rl_loading&=&(RelativeLayout)&findViewById(R.id.rl_loading);&&&&&&&&&&&&&&&&&&&&mWebView&=&(WebView)&findViewById(R.id.mWebView);&&&&&&&&&&&&&&&&&&&&initWebView();&&&&&&&&&&&&&&&&&&&&mWebView.setWebViewClient(new&WebViewClient()&{&&&&&&&&&&&&&&&&@Override&&&&&&&&&&&&&&public&void&onLoadResource(WebView&view,&String&url)&{&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&Log.i(TAG,&&onLoadResource&url=&+url);&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&super.onLoadResource(view,&url);&&&&&&&&&&&&&&}&&&&&&&&&&&&&&&&@Override&&&&&&&&&&&&&&public&boolean&shouldOverrideUrlLoading(WebView&webview,&String&url)&{&&&&&&&&&&&&&&&&&&&&Log.i(TAG,&&intercept&url=&+url);&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&webview.loadUrl(url);&&&&&&&&&&&&&&&&&&&&return&true;&&&&&&&&&&&&&&}&&&&&&&&&&&&&&&&@Override&&&&&&&&&&&&&&public&void&onPageStarted(WebView&view,&String&url,&Bitmap&favicon)&{&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&Log.e(TAG,&&onPageStarted&);&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&rl_loading.setVisibility(View.VISIBLE);&//&显示加载界面&&&&&&&&&&&&&&}&&&&&&&&&&&&&&&&@Override&&&&&&&&&&&&&&public&void&onPageFinished(WebView&view,&String&url)&{&&&&&&&&&&&&&&&&&&&&String&title&=&view.getTitle();&&&&&&&&&&&&&&&&&&&&Log.e(TAG,&&onPageFinished&WebView&title=&&+&title);&&&&&&&&&&&&&&&&&&&&tv_topbar_title.setText(title);&&&&&&&&&&&&&&&&&&tv_topbar_title.setVisibility(View.VISIBLE);&&&&&&&&&&&&&&&&&&&&rl_loading.setVisibility(View.GONE);&//&隐藏加载界面&&&&&&&&&&&&&&}&&&&&&&&&&&&&&&&@Override&&&&&&&&&&&&&&public&void&onReceivedError(WebView&view,&int&errorCode,&String&description,&String&failingUrl)&{&&&&&&&&&&&&&&&&&&&&rl_loading.setVisibility(View.GONE);&//&隐藏加载界面&&&&&&&&&&&&&&&&&&&&Toast.makeText(getApplicationContext(),&&&,&&&&&&&&&&&&&&&&&&&&&&&&&&Toast.LENGTH_LONG).show();&&&&&&&&&&&&&&}&&&&&&&&&&});&&&&&&&&&&&&mWebView.setWebChromeClient(new&WebChromeClient()&{&&&&&&&&&&&&&&&&@Override&&&&&&&&&&&&&&public&boolean&onJsAlert(WebView&view,&String&url,&String&message,&JsResult&result)&{&&&&&&&&&&&&&&&&&&&&Log.e(TAG,&&onJsAlert&&&+&message);&&&&&&&&&&&&&&&&&&&&Toast.makeText(getApplicationContext(),&message,&Toast.LENGTH_SHORT).show();&&&&&&&&&&&&&&&&&&&&result.confirm();&&&&&&&&&&&&&&&&&&&&return&true;&&&&&&&&&&&&&&}&&&&&&&&&&&&&&&&@Override&&&&&&&&&&&&&&public&boolean&onJsConfirm(WebView&view,&String&url,&String&message,&JsResult&result)&{&&&&&&&&&&&&&&&&&&&&Log.e(TAG,&&onJsConfirm&&&+&message);&&&&&&&&&&&&&&&&&&&&return&super.onJsConfirm(view,&url,&message,&result);&&&&&&&&&&&&&&}&&&&&&&&&&&&&&&&@Override&&&&&&&&&&&&&&public&boolean&onJsPrompt(WebView&view,&String&url,&String&message,&String&defaultValue,&JsPromptResult&result)&{&&&&&&&&&&&&&&&&&&&&Log.e(TAG,&&onJsPrompt&&&+&url);&&&&&&&&&&&&&&&&&&&&return&super.onJsPrompt(view,&url,&message,&defaultValue,&result);&&&&&&&&&&&&&&}&&&&&&&&&&});&&&&&&&&&&&&&&&&&&&&mWebView.loadUrl(url);&&&&&&}&&&&&&&&private&void&initWebView()&{&&&&&&&&&&&&&&&&&&&&mWebView.getSettings().setJavaScriptEnabled(true);&&&&&&&&&&mWebView.getSettings().setRenderPriority(RenderPriority.HIGH);&&&&&&&&&&mWebView.getSettings().setCacheMode(WebSettings.LOAD_DEFAULT);&&//设置&缓存模式&&&&&&&&&&//&开启&DOM&storage&API&功能&&&&&&&&&&mWebView.getSettings().setDomStorageEnabled(true);&&&&&&&&&&//开启&database&storage&API&功能&&&&&&&&&&mWebView.getSettings().setDatabaseEnabled(true);&&&&&&&&&&&String&cacheDirPath&=&getFilesDir().getAbsolutePath()+APP_CACAHE_DIRNAME;&&//&&&&&&String&cacheDirPath&=&getCacheDir().getAbsolutePath()+Constant.APP_DB_DIRNAME;&&&&&&&&&&Log.i(TAG,&&cacheDirPath=&+cacheDirPath);&&&&&&&&&&//设置数据库缓存路径&&&&&&&&&&mWebView.getSettings().setDatabasePath(cacheDirPath);&&&&&&&&&&//设置&&Application&Caches&缓存目录&&&&&&&&&&mWebView.getSettings().setAppCachePath(cacheDirPath);&&&&&&&&&&//开启&Application&Caches&功能&&&&&&&&&&mWebView.getSettings().setAppCacheEnabled(true);&&&&&&}&&&&&&&&&&&&/**&&&&&&*&清除WebView缓存&&&&&&*/&&&&&&public&void&clearWebViewCache(){&&&&&&&&&&&&&&&&&&&&//清理Webview缓存数据库&&&&&&&&&&try&{&&&&&&&&&&&&&&deleteDatabase(&webview.db&);&&&&&&&&&&&&&&&deleteDatabase(&webviewCache.db&);&&&&&&&&&&}&catch&(Exception&e)&{&&&&&&&&&&&&&&e.printStackTrace();&&&&&&&&&&}&&&&&&&&&&&&&&&&&&&&//WebView&缓存文件&&&&&&&&&&File&appCacheDir&=&new&File(getFilesDir().getAbsolutePath()+APP_CACAHE_DIRNAME);&&&&&&&&&&Log.e(TAG,&&appCacheDir&path=&+appCacheDir.getAbsolutePath());&&&&&&&&&&&&&&&&&&&&File&webviewCacheDir&=&new&File(getCacheDir().getAbsolutePath()+&/webviewCache&);&&&&&&&&&&Log.e(TAG,&&webviewCacheDir&path=&+webviewCacheDir.getAbsolutePath());&&&&&&&&&&&&&&&&&&&&//删除webview&缓存目录&&&&&&&&&&if(webviewCacheDir.exists()){&&&&&&&&&&&&&&deleteFile(webviewCacheDir);&&&&&&&&&&}&&&&&&&&&&//删除webview&缓存&缓存目录&&&&&&&&&&if(appCacheDir.exists()){&&&&&&&&&&&&&&deleteFile(appCacheDir);&&&&&&&&&&}&&&&&&}&&&&&&&&&&&&/**&&&&&&*&递归删除&文件/文件夹&&&&&&*&&&&&&&*&@param&file&&&&&&*/&&&&&&public&void&deleteFile(File&file)&{&&&&&&&&&&&&Log.i(TAG,&&delete&file&path=&&+&file.getAbsolutePath());&&&&&&&&&&&&&&&&&&&&if&(file.exists())&{&&&&&&&&&&&&&&if&(file.isFile())&{&&&&&&&&&&&&&&&&&&file.delete();&&&&&&&&&&&&&&}&else&if&(file.isDirectory())&{&&&&&&&&&&&&&&&&&&File&files[]&=&file.listFiles();&&&&&&&&&&&&&&&&&&for&(int&i&=&0;&i&&&files.&i++)&{&&&&&&&&&&&&&&&&&&&&&&deleteFile(files[i]);&&&&&&&&&&&&&&&&&&}&&&&&&&&&&&&&&}&&&&&&&&&&&&&&file.delete();&&&&&&&&&&}&else&{&&&&&&&&&&&&&&Log.e(TAG,&&delete&file&no&exists&&&+&file.getAbsolutePath());&&&&&&&&&&}&&&&&&}&&&&}&
简洁版代码:
view plaincopy
System.out.println(&getCacheDir:&&+WebViewActivity.this.getCacheDir());&&&&&&System.out.println(&PackageResourcePath():&&+WebViewActivity.this.getPackageCodePath());&&&&&&System.out.println(&getCacheDir:&&+WebViewActivity.this.getPackageResourcePath());&&&&&&System.out.println(&FilesDir:&&+WebViewActivity.this.getDatabasePath(&webview.db&).getPath());&&&&&&System.out.println(&FilesDir:&&+WebViewActivity.this.getFilesDir().getPath())&&
view plaincopy
view plaincopy
03-31&11:54:52.094:&I/System.out(22224):&getCacheDir:&/data/data/com.liao.webview/cache&&03-31&11:54:52.094:&I/System.out(22224):&PackageResourcePath():&/data/app/com.liao.webview-1.apk&&03-31&11:54:52.115:&I/System.out(22224):&getCacheDir:&/data/app/com.liao.webview-1.apk&&03-31&11:54:52.115:&I/System.out(22224):&FilesDir:&/data/data/com.liao.webview/databases/webview.db&&03-31&11:54:52.154:&I/System.out(22224):&FilesDir:&/data/data/com.liao.webview/files&&03-31&11:54:52.265:&I/ActivityManager(59):&Displayed&activity&com.liao.webview/.WebViewActivity:&418&ms&(total&418&ms)&&
view plaincopy
view plaincopy
//&clear&the&cache&before&time&numDays&&&&&&&private&int&clearCacheFolder(File&dir,&long&numDays)&{&&&&&&&&&&&&&&&&int&deletedFiles&=&0;&&&&&&&&&&&&&&&if&(dir!=&null&&&&dir.isDirectory())&{&&&&&&&&&&&&&&&&&&&&&&&try&{&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&for&(File&child:dir.listFiles())&{&&&&&&&&&&&&&&&&&&&&&&if&(child.isDirectory())&{&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&deletedFiles&+=&clearCacheFolder(child,&numDays);&&&&&&&&&&&&&&&&&&&&&&&&&&&&}&&&&&&&&&&&&&&&&&&&&&&if&(child.lastModified()&&&numDays)&{&&&&&&&&&&&&&&&&&&&&&&&&&&&if&(child.delete())&{&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&deletedFiles++;&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&}&&&&&&&&&&&&&&&&&&&&&&}&&&&&&&&&&&&&&&&&&}&&&&&&&&&&&&&&&&&&&&&&&}&catch(Exception&e)&{&&&&&&&&&&&&&&&&&&&&&e.printStackTrace();&&&&&&&&&&&&&&}&&&&&&&&&&&}&&&&&&&&&&&&&return&deletedF&&&&&&&}&&&&&
view plaincopy
//优先使用缓存:&&WebView.getSettings().setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);&&&&
view plaincopy
&p&//不使用缓存:&&WebView.getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE);&&/p&&&
view plaincopy
view plaincopy
退出的时候加上下面代码&&
view plaincopy
File&file&=&CacheManager.getCacheFileBaseDir();&&&&&&&if&(file&!=&null&&&&file.exists()&&&&file.isDirectory())&{&&&&&&&&for&(File&item&:&file.listFiles())&{&&&&&&&&&item.delete();&&&&&&&&}&&&&&&&&file.delete();&&&&&&&}&&&&&&&&&&context.deleteDatabase(&webview.db&);&&&&&&context.deleteDatabase(&webviewCache.db&);&&
&此文从网络中自动搜索生成,不代表本网站赞成被搜索网站的内容或立场
&&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&&&&&&&& 17:41:30
软件世界网- &2014 蜀ICP备号 三峰网旗下网站这篇并没有整理完. 提前放出,是因为有朋友关心这部分.我就尝试抛砖引玉吧. 暂时实在没精力把 这部分的标准翻译完整. 放在这里算是督促下自己,尽快写完吧.
我建议您, 只要简单看看最后面的总结部分即可.. & 因为前面只是我对草案的简单翻译 和个人理解.难免有错漏之处.如果您看的话,建议仅供参考,我无法保证期准确性.
另外,此文再我的evernote中.大概是今年2月份左右. 现在可能草案有新的改动.也请留意.
当前浏览器支持情况:
IE10? (至少,似乎 IE10 pp2还不支持. 但是 caniuse上列出的是有支持的.也许是那个win8上的update会有吧?)
Opera10.6+
Safari4.0+
Firefox3.0+
IOS Safari3.2+
android2.1+&
offline web applications相关标准 : &
manifest文件相关标准 :&
manifest文件解析流程:&
application&cache&selection&algorithm :
Changes&to&the&networking&model&:&
Offline Web applications
关于manifest.
首先 manifest 的 contentType = text/cache-manifest
然后,其扩展名,建议为 "appcache"
Type name :&text
Subtype name :&cache-manifest
Required parameters :&No parameters
Optional parameters :&No parameters
Encoding considerations :&Always UTF-8.
隐私相关:manifests 设计上,没有什么直接的敏感信息问题.除非,manifests文件自身包含了敏感信息.
另外,这东西是专门应用于 Web browsers的.
note : (此部分并非标准,而是建议)
& & &1. 标准鼓励,缓存包含manifest清单的页面,所以实际上,即使我们不显示的把包含manifest的页面,列在manifest缓存清单中,这个页面也会被缓存的.
& & &2. HTTP相关的缓存头域 以及 https的缓存页面限制,将被manifest所无视. 所以在用户代理 更新页面之前,它是不会过期的. 也就是说,即使是一个HTTPS的东西.也可以脱机工作.
简单demo :&
&!DOCTYPE HTML&
&html manifest="clock.appcache"&
& &title&Clock&/title&
& &script src="clock.js"&&/script&
& &link rel="stylesheet" href="clock.css"&
& &p&The time is: &output id="clock"&&/output&&/p&
Manifest 的语法:
CACHE MANIFEST
# 上面这行是必须的
# 这是一行注释
# 在这个文件中的任何地方都可以添加
# 它们全部都会被忽略
& # 在注释之前可以有空格
& # 但必须是在单行前
# 空行也会被忽略
# 这些列在最开始的文件都是需要被缓存的
# 或者是那些列在"CACHE:"里的, "CACHE"头必须写在这些文件之前,如同
# 下面写好的那样
images/sound-icon.png
images/background.png
# 注意,每个文件必须单独一行
# 在线白名单中出现的这个文件,它不会被缓存,并且,
# 对该文件的引用,将绕过缓存,总是会
# 从网络中获取目标(或在用户离线时,尝试从网路上获取)
我们也可以书写成这样:
CACHE MANIFEST
style/default.css
images/sound-icon.png
images/background.png
离线应用程序缓存清单可以使用相对路径或绝对URL地址:
CACHE MANIFEST
/main/home
/main/app.js
/settings/home
/settings/app.js
/check.png
/cross.png
&&&&&下面的清单定义了一个捕捉所有错误(应该指http错误,导致无法正常显示)的页面,它会在用户离线时被显示出来。它同时也指定在线白名单通配符标记(online whitelist wildcard flag)为开启(open)状态(下面在相关概念介绍部分会有提及),即,在访问其他站点资源的时候不会被阻止(blocked,是指访问其他站点资源,不受manifest影响.)。(相同站点的资源已经不会被阻止了,因为有捕捉所有的备用命名空间的通配符)只要站点上所有的页面引用了这个缓存清单,这些页面,都将全部从本地缓存中取得,就如同它们实际上被读取一样,随后,那些被命中的同名页面,会立即从缓存中加载,直到缓存清单发生了改变,否则,那些页面将不再从服务端读取。当缓存清单发生改变时,所有的文件都将被重新下载。因为子资源并没有别列在清单的明示域,所以,子资源NETWORK的通配符匹配了,这时候,如css样式表,图片等等,无论如何,只能通过常规的HTTP缓存语义进行缓存。
CACHE MANIFEST
/ /offline.html
应用程序缓存下载过程(application cache download process)步骤:
1. 可选,等待,直到通过用户授权开始应用程序缓存下载过程(application cache download process),且user agent确认网络可用。这可能包括在用户明确该站点选用缓存前,或者需要向用户询问授权前,什么都不做。在这时,算法规则&&&&&&&&&&&&&&&&&&&&永远不会被执行。(当前步骤特意为那些运行在有空间限制或隐私高度敏感的user agent环境而设计)
2. 自动的, 为了避免竟态条件(race conditions),执行下列子步骤:
&&&&&(1). 选择合适的子步骤:
& & & & & & & &.如果这些步骤是以一个绝对URL,来调用,用于识别一个manifest则:
& & & & & & & & & & 令 manifest URL 为这个绝对URL.
& & & & & & & & & & 如果没有一个用manifest URL,作为标识的application cache group,则创建一个新的application cache group.并以 manifest作为其标识.
& & & & & & & & & & 初始化时,这个application cache并没有属于它的application cache, 但会在接下来的算法中创建.
& & & & & & & &.如果这些步骤是以一个application cache group调用的则:
& & & & & & & & & & 令manifest URL为application cache group所对应的manifest的绝对URL标识,以用于更新.
& & & & & & & & & & 如果application cache group被标为废弃状态.则终止这次应用程序缓存的下载过程. application cache group被标为废弃,会发生在下载过程第一步,在等待manifest下载时,发现缓存清单返回404或410的情况.
& & &(2). 令cache group为 application cache group并以 manifest URL 为其标识.
& & &(3). 如果这些步骤是以一个主体资源调用的, 则把这个资源与其对应的Document一并添加到cache group的待定主体项列表中去.
& & &(4). 如果这些步骤是以一个cache host调用,并且cache group的status的值为checking 或downloading(这里不是笔误,整个8个子步骤是为了避免静态条件的发生,是1 by 1的查看步骤. 所以隐含的意思是,checking是必须要先触发的.如果status是downloading,又没触发过checking事件,则就要触发一次checking,即使当前的status是downloading也要如此. 然后再进入步骤5.),则发起一个post-load (参考:部分,post-load task.这里指事件队列. 对于事件来说,异步的在一个具体的事件源对象上,派发一个事件,就是一个任务.那么 此时的task queue 就是一个异步事件队列. 类似的还有 HTML parsing 队列等等.)任务队列.并,在cache host所属的ApplicationCache(对象)上触发一个可取消的checking事件.如果用户代理实现了所谓显示缓存过程(shows caching progress,这东西用户代理可以选择性实现,并非标准硬性规定.即给用户显示资源的缓存过程、进度信息.),则该事件的默认行为,必须是,用户代理,通过某种方式提示用户,当前正在检测是否可以进行应用资源的下载.
& & &(5).&如果这些步骤是以一个cache host调用,并且cache group的status的值为downloading,则发起一个post-load 任务队列.并,在cache host所属的ApplicationCache(对象)上触发一个可取消的downloading事件.如果用户代理实现了所谓显示缓存过程,则该事件的默认行为,必须是,用户代理.通过某种方式提示用户,正在进行应用资源的下载.
& & &(6). 如果一个application cache 要进行update的同时, 其status是 checking 或downloading,则就要终止当前的application cache download process.&
& & &(7). 把cache group 的status设置为 checking状态.
& & &(8). 为 cache group中每个 cache host相关联的application cache,发起一个post-load 任务队列. 并在cache host对应的ApplicationCache(指window.applicationCache object)上触发一个,可取消的,叫做 checking 的简单事件(simple event,指直接继承自Event接口的,除非另有说明,否则默认没有冒泡行为,也不可取消的事件类型.)如果用户代理实现了所谓显示缓存过程,则该事件的默认行为,必须是,用户代理.通过某种方式提示用户,正在检测应用资源的是否可更新.
& & &ps: 个人理解2步骤中的8个子步骤,所谓避免静态条件,就是指一个application cache group中多个application cache 同时各自更新cache, 网络资源竞争.等等现象.其实我们并不需要太关系具体细节.
& & &Note: 剩余的步骤全都异步进行.
& & &如果cache group 已经具备一个application cache,则进入尝试更新流程(upgrade attempt), 否则进入尝试缓存流程(cache attempt)
3. 如果这是在做 cache attempt(缓存尝试),那么此算法就一定是以一个 cache host调用的. 则,发起一个post -load 任务队列,在cache host对应的ApplicationCache上,触发名为 checking ,且可被取消的简单事件.如果用户代理实现了所谓shows caching progress则该事件的默认行为,必须是用户代理.通过某种方式提示用户,正在检测应用资源的是否可更新.
4. 获取manifest: 以同步标识设置的方式通过manifest URL 获取manifest.
& & 如果manifest文件的 MIME type是 text/cache-manifest. 则按照manifest解析规则来进行解析(参考:).并获取明示项、备用项、备用名称空间、在线白名单项、以及在线白名单通配符标记的值.
5. 如果因404或401响应或其他类似的原因导致,获取manifest失败,则执行下面的子步骤:
& & &(1). 把 cache group标为废弃. 如果这时候,该cache group中,没有一个Document与一个application cache相关联,则这个cache group就没有任何存在的价值了.
& & &(2). 令task list 为一个空的任务列表.
& & &(3). 在cache group中,每一个关联了一个application cahe的cache host所对应的ApplicationCache对象上触发一个,可取消的、名为 obsolete 的简单事件. 并把这个事件添加到 task list中去.&如果用户代理实现了所谓shows caching progress则该事件的默认行为,必须是用户代理.通过某种方式提示用户,应用程序在离线状态下,将不可用.
& & &(4). 在cache group的待定主体项清单中的每一项的Document所对应的ApplicationCache对象上,创建一个任务并触发一个 可取消的,名为 error(并不是 obsolete)的简单事件.如果用户代理实现了所谓shows caching progress则该事件的默认行为,必须是用户代理.通过某种方式提示用户,用户代理为应用离线工作所作的保存(缓存)失败了.
& & &(5). 如果cache group的某个 application cache的 completeness flag为 incomplete(即某个application cache的完整性标记为未完成),则抛弃之.
& & &(6).移除可能存在的,所有表示该cache正在更新的 ui信息.
& & &(7). 令cache group的status为"idle" (空闲状态).
& & &(8). 为任务列表中的每个人物,发起一个post-load任务队列.
& & &(9). 取消应用程序缓存下载(application cache download)过程.
6. 另外,如果因其他原因导致获取manifest失败(举例来说,服务器返回了其他4xx,5xx响应,或类似的事情,又或者是DNS错误.或连接超时.又或者检测魔法签名时,解析manifests失败.).或者服务器返回一个重定向,或者manifest的MIME type不是text/cache-manifest .则进入缓存失败步骤(cache failure steps,在后面解释.):
7. 如果处于尝试更新流程,并且新下载的manifest文件.与cachegroup中最新的application cache的manifest,完全相同,或者下载文件时服务器端返回"304 not modified" 或其他等价的结果.则执行下面的子步骤:
& & &1. 令 cache 为 cache group 中最新的application cache.
& & &2. 令 task list 为一个 空的任务列表.
& & &3. &未完成... 待续.
ApplicationCache对象:
& & &&本章节属于非规范性内容.
& & &当用户访问一个声明了manifest的页面时, 浏览器会尝试更新缓存. 通过获取一份manifest文件的副本来实现校验. 如果manifest相对上一次读取该文件,有变化,则就要更新全部清单中列出的资源.
& & &在这个过程中,在ApplicationCache对象上会触发一系列的事件,来使脚本保持缓存更新的状态,以便用户可以得到适当地通知。这些事件如下:
& & & & & & &
& & &ApplicationCache对象相关事件:
被触发的时间
下一个可能的事件
当用户代理校验是否需要更新,或首次尝试下载manifest文件的时候,此事件,总是ApplicationCache对象相关事件序列中,第一个发生的.
noupdate, downloading, obsolete , error
manifest没有任何改变,确认不需要更新的时候.
序列中最后一个事件.
downloading
用户代理找到一个更新(针对cache group),并获取该资源,或首次下载缓存清单中的全部资源的时候.
progress, error, cached, updateready
ProgressEvent
用户代理下载缓存清单中所列出的资源时发生.(每个resource被下载都会触发一次该事件.)
progress, error, cached, updateready
用户代理下载某资源结束并缓存该资源后发生.
序列中最后一个事件.
updateready
缓存清单中的资源被重新下载后,并且script可以调用 swapCache()方法去替换缓存时
序列中最后一个事件.
manifest文件 404 或 410时, 缓存会被删除.然后触发此事件.
序列中最后一个事件.
1. mainfest 404 或410时.
2. manifest没有改变,但是无法正确定位并下载引入manifest文件的页面的时候.
3. 获取某个在缓存清单中的资源时,发生某些严重的错误.
4. 当缓存(猜测指的是manifest,而不是指清单上的资源)更新时,manifest发生了变化..
序列中最后一个事件.
对应4: 用户代理会随时尝试再次获取manifest文件.
ApplicationCache对象属性
& & & & & .status :&
& & & & & & & &0 : &UNCACHED (代表未缓存)
& & & & & & & &1 : &IDLE (表示空闲状态)
& & & & & & & &2 : &CHECKING(表示增在检测缓存新鲜度)
& & & & & & & &4 : &UPDAEREADY(空闲+ !obsolete + application cache不能为刚刚更新的.)
& & &&&&&&&&&&&&&&&&
& & &ApplicationCache对象方法
& & & & &&.update()
& & & & & 主动更新所有缓存清单中列出的缓存资源.
& & &&&&&&
& & & & & .swapCache()方法(标准地址:)
& & & & & 简单来说就是,当updateready后,我们调用这个方法,就达到了用新文件替换老缓存文件的目的.
& & & & & .abort()方法. 2012年1月,草案更新,追加的方法目前似乎没有浏览器实现.. 参考:&
& & & & & &原文只有一段描述:
&&&&&&&&&&If the&abort()&method is invoked, the user agent must&send a signal&to the current&&for the&&with which the&object's&&is associated, if any. If there is no such&, or if does not have a current&, then do nothing.
& & & & &&
& & &&&&&&
相关概念:&
& & &. application cache 由一组缓存资源组成的集合,他可能包括下面这些东西: (参考地址)
& & & & & & & &.一个或多个资源,通过url进行识别,可以分为下面几种类别:
& & & & & & & & & & & & &主体项(Master entries)
& & & & & & & & & & & & &&&&&&注:这些文档被添加到缓存中是因为浏览环境上下文(browsing context)被导航(navigated)到那些文档中(这说的就是引入了manifest的页面.)
& & &&&&&&
& & & & & & & &&&&&&&&&&&.缓存清单(Manifest)
& & & & & & & & & & & & &&&&&&注:这是与在主体项html元素的manifest属性中给出的URL相对应的资源。它会在application cache对象的download process过程中被取出并进行处理。所有的主体项(master entries)必须与与manifest文件同源(same origin)
& & & & & & & & & & & & &.明示项(Explicit entries)
& & & & & & & & & & & & &&&&&&注:这些都是在缓存清单的明示区域(explicit section)中列出的资源
& & & & & & & & & & & & &.备用项(Fallback entries)
& & & & & & & & & & & & & & & 注:这些都是在缓存清单的备用区域(fallback section)中列出的资源
& & & & & & & & & & & & &
&&&&&&&&&&&&&&&.零个或多个备用名称空间(fallback namespaces) & 的URL
& & & & & & & & & & 注:与备用项存在映射关系. &备用项就是备用名称空间的备用项,也就是说备用名称空间所代表的url,或其通配符所匹配的那些url,一但访问不能,就要以备用项url作为后备使用.
& & & & & & & &.零个或多个在线白名单名称空间(online whitelist namespaces)的URL
& & & & & & & & & &&注:在白名单区域出现的url,或被其通配符所匹配的url,都不会从离线应用程序缓存加载资源,而总是尝试从网络中获取(HTTP Cache是有效的.).
& & & & & & & &.在线白名单通配符标记(online whitelist wildcard flag),分别为open 和 blocking
& & & & & & & & & & 注:白名单的open状态(以通配符"*"作为首个token的白名单,则进入open状态,表示匹配所有URL,如果*不作为首个token出现,会被忽略.)表示, 所有被在线白名单名称空间 ,所匹配的url,如果没有显示的出现在CACHE项中,则都视为 该资源存在于白名单中(因为进入open状态,此时这些资源,都是遵守HTTP缓存头域相关缓存策略的.).&blocking状态(即白名单内容首个token不是"*"的状态.则此时白名单中是列出具体的url,或者前缀匹配的表达式的.被匹配的部分则,同open状态匹配一样.可以根据HTTP缓存头域进行正常的访问.),则表示,manifest中没有显式出现过(也不被各类通配符所匹配的)url(自然也包括没有被白名单明确匹配的URL), 会被manifest无效处理.(无效处理,浏览器的实现就是获取不能.无法下载.)
& & & & &&&&&&&&&&& 参考:&中的描述.会更明确的说明,无效处理,指的就是下载不能.
& & & & & & & & && (参考:如果某个资源文件被列在了明示区域(explicit section)或是备用区域(fallback section)中的一个备用项目实体(fallback entry),那么,该资源也可以从缓存中读取,不论它是否匹配到了其他的备用命名空间(fallback namespaces)或在线白名单命名空间(online whitelist namespaces)的项目实体.)
& & & & & & & &.应用程序缓存的完整性标记(application cache completeness flag),状态分为complete和incomplete
& & & & & & & &.应用程序缓存组(application cache group) ,即是借助manifest的url来进行分组一组组的应用程序缓存(application cache).(也就是说,具有相同 manifest url但是cache host不同的 application cache被放置在一个cache group里)
& & & & & & & & & & & & &. 一组application cache,后出现的是更则是新鲜的,也就是说,一组application cache.是按时间顺序排序的
& & & & & & & & & & & & &. 在application cache group中,只有最新的application cache的完整性标记(completeness flag)值为&不完整&的(incomplete);其他的都为&完整的&(complete)
& & & & & & & & & & & & &. 每个application cache group 都有一个更新状态(update status),其值为以下其中一种:idle, checking, downloading
& & & & & & & & & & & & &.&符合的应用程序缓存(relevant application cache)是在该缓存组(group)中最新的(newest)且被标记为&已完成&(complete)的那个application cache。
& & & & & & & & & & & & &. 每个application cache group都有一个待定的主体项清单(list of pending master entries).清单中的每一项,都由一个资源以及对应的一个Document对象所组成.&
& & & & & & & & & & & & & &它们用于在应用缓存下载过程中确认新的主体项是否被缓存. &
& & & & & & & & & & & & &.application cache group可以被标记为作废的(obsolete),即在检查已存在的application cache group时,必须忽略它们.
& & & & & & & & & & & & &.application cache group中的诸多application cache,的清单都是相同的,而用户代理要从relevant application cache中选出,用户最可能需要的那一个,就要考虑下面这些因素:
& & & & & & & & & & & & & & & & & &1.哪个application cache是最近被更新的
& & & & & & & & & & & & & & & & & &2.哪些应用程序缓存是用来列出那些用户决定需要检查的新资源,且
& & & & & & & & & & & & & & & & & &3.哪些应用程序缓存是用户偏好的
& & & & & & & & & & & & &
& & & & & & & &.缓存宿主(cache host)是一个Document对象,或一个SharedWorkerGlobalScope对象(参考:).他们可以和一个application cache关联.
& & &&&&&&&&&&&&&&&&&&&&&Document对象在初始时并未与application cache关联,而是在一个较早的页面加载过程中,当进到in the parser过程,在navigation这块,由cache selection引发,从而使得它们进行关联。
& & & & & & & & & & & & & & & .in the parser :
& & & & & & & & & & & & & & & &&&&&简单的说,这里是指html parse的过程中,遇到html manifest =xxx的部分,就使用这个xxx 的绝对url,进行 所谓缓存算法选择流程.(缓存算法选择,会在后面解释.)
& & & & & & & & & & & & & & & .navigation :
& & & & & & & & & & & & & & & & & &navigation是针对资源的导航过程.大概步骤有20步.很繁杂.
& & & & & & & & & & & & &ps: cache host ,说白了就是, &window.applicationCache 中 window所对应的当前页这个Document. 也就是说 Document要对应一个ApplicationCache对象用于控制,一组application cache,即 application cache group
. 引入 manifest方式为 : &&html manifest="name.appcache"&
. manifest的加载是晚于页面其他资源的.
. manifest的contentType应为 : text/cache-manifest
. 建议其扩展名为 : appcache
. manifest文件本质是一个,要采用UTF-8编码方式编码的文本文件.
. 引入manifest的页面,即使没有被列入缓存清单中,仍然会被用户代理缓存.
. manifest文件从标准角度来说,是不能直接从缓存读取的.即使像上一条说的,你明确的把manifest放入另一个清单中.至少也是服务器尝试返回304.再去读缓存.(注1)
. 在线的情况下,用户代理每次访问页面,都会去读一次manifest.如果发现其改变, 则重新加载全部清单中的资源(注2).
. 对于浏览器来说,manifest的加载是要晚于其他资源的. 这就导致check manifest的过程是滞后的.发现manifest改变.所有浏览器的实现都是紧随这做静默更新资源.以保证下次pv,应用到更新.
. manifest文件必须与引入它的页面同源.
. 如果manifest文件是一个https或其他加密协议资源,则其清单中明示项(explicit section)的资源都必须和manifest同源.
. 备用项和备用名称空间,必须与当前的manifest同源.
. 备用项如果发生命中,则也会被缓存.
. 明示项和备用项优先级高于白名单.
. 白名单使用通配符"*". 则会进入白名单的open状态. 这种状态下.所有不在相关Cache区域出现的url都默认使用HTTP相关缓存头策略.
. 白名单使用具体的前缀匹配或更具体的URL,则都属于blocking状态.这种状态下,白名单所匹配的,非Cache区域出现的URL,与open的*匹配的结果一致,但是不在白名单中,又不在整个manifest的资源,会block.也就是访问,加载不能.
. manifest中的url ,必须与manifest使用相同的协议.
. 一个manifest的明示项中可以包含另一个manifest.(但这种设计,我认为很2.)
. manifest中的url,不应有"#" 锚点部分出现(比如 abc.htm#1,如果出现#,则 #以及后面部分,会被丢弃.)
. 建议使用&!DOCTYPE html& DTD, 因为据说,某些浏览器会因为,进入非标准模式,而无视manifest.
& & &(我本人没有实测,但我个人猜测,如果有这样一款浏览器,那么它很可能就是IE10. 因为IE10进入兼容模式,很多html5草案的API都使用不能.比如performance API)
. 被清单缓存的资源,是无视http cache 相关 头域, 或其是否是https资源的.
. 相同备用名称空间,不能重复出现在 备用区域中.
. 不应有相包含的备用名称空间出现在备用区域中(因为前缀匹配的原因.出现包含,显然是多余的,如果真有一个URL同时匹配两个通配符.那么就以更长的那个为准.).
. 备用名称空间 和 白名单名称空间 都使用前缀匹配模式.即支持通配符匹配模式.(可以放心的是 ///abc 是不匹配 ///ab的,因为///ab&实际上是///ab/)
. 前缀匹配对端口的匹配是宽松的.如:80/a.png 就会被 /所匹配.
.&在写相对路径的时候 不是相对 引入它的html& 而是相对 manifest文件所在目录的
. 一但manifest检测,需要更新,导致所有cache资源更新。其中manifest会再次加载一次.(所以给所有缓存资源配置合理的304机制.是十分有必要的.)
. 一组不同的页面引入相同的manifest文件时,这组页面的即构构成一个group.并已document作为标识,来区分他们.其中任何一个的manifest或资源更新,甚至是检测都会触发其他页面的applicationCache的相应事件.
. applicationCache.update(), 只会立刻检测manifest文件,而不会更新相应资源.并且会遵守304相关http缓存头.
. a,b两个页面,引入相同资源,但a有使用manifest,而b没有.那么,即使a页面缓存了资源.b页面也不会有效.而且b页面强制更新了资源.a页面的缓存也不会因为b的更新,而更新.
. a页面引入manifest,缓存的资源, 在浏览器地址栏中直接访问,则也命中offline application的缓存.刷新也如此.至少chrome,FF都是如此实现的.
. a,b两个页面,分别引入A,B两个manifest文件,且分别缓存相同的一个资源R,则 如果此时更新R,然后更新B.则.b刷新后重新获取资源R,但是a的R资源缓存副本是不会被更新的.
. a,b两个页面,引用同一份manifest A. 则更新A,更新R,刷新b, b对应的R资源更新后,a的R资源副本也会随之更新. 这就是cache group的机制.因为a和b对应的application cache,同属于同一个application cache group.
.&建议为manifest文件配置304相关 头域时,也配置expires和cache-control : max-age.因为chrome,safari,以及android,只有304相关头域,而没有expires 或 max-age时,不会有304,而只会是200, opera则无视一切http cache头域.总是200.
& (浏览器的实现都有问题,webkit的问题是,没有遵守http协议.因为304相关头域是足矣使浏览器是具备资源副本,并做握手的. 而opera则完全无视http缓存头域.更加不靠谱. (IE10 pp2,FF系列.不方便测试))
注1:&FF的实现有bug.他有自己的时间管理,在短时间内重复请求一个manifest,FF会有直接从cache中读取的情况出现.即使,我们主动使用applicationCache.update().而 FF9+开始,这个所谓的短时间,被延长了很久,至少我个人没有实测出到底要多久.因为同样一个manifest,有时候他就要我等很久,有时候很短暂(暂时没有找出具体规律,至少和Expires,max-age等头域无关.). 这是不符合规范的做法.规范中唯一允许,不经验证,直接从cache读取manifest的就是,如在地址栏直接get manifest或类似的的情况.
注2 : 所谓重新加载, 是依然遵守http 的缓存相关头域的, android webkit browser, chrome ,FF6- 等. 但是FF7+ 开始有了优化, 当缓存资源的http Expires 等相关缓存头域显示该资源没有过期时,FF6+依然会去本地缓存去的资源. 而不像其他浏览器,则会尝试带着304相关头域发起http请求.
阅读(...) 评论()

我要回帖

更多关于 cache可以删除吗 的文章

 

随机推荐