manifest是html5提供的离线web应用解决方案,它的作用有两个:
1. 连网情况下,访问使用manifest的页面时(之前曾经访问过),会先加载一个manifest文件,如果这个manifest文件没有改变,页面相关的资源便都来自浏览器的离线缓存,不会再有额为的网络请求,从而大大提高页面相应时间
2. 断网时,在浏览器地址栏输入页面url,仍然能够正常显示页面,以及正常使用不依赖ajax的功能
之前曾想在手机webview的开发中使用这种功能,但权衡再三,也没有使用,其中一个原因,便是manifest配置太繁琐,很不利于开发和维护,比如,一个正常的manifest文件是这样的:
test.manifest
CACHE MANIFEST # VERSION 0.3 # 直接缓存的文件 CACHE: /index.html /img/x1.png /img/x2.png /img/x3.png /js/xx.js /css/xx.css # 需要在线访问的文件 NETWORK: # 替代方案 FALLBACK: |
也就是说,
但是,离线缓存这个功能又是如此的诱人,所以就想着用其他方式绕开繁琐的配置
首先,test.manifest文件的扩展名必须是manifest静态文件,不能动态声称,于是便想使用php来生成manifest文件,对于apache服务器,再网站根目录下添加.htaccess文件,将/xxx.manifest请求,转给/manifest/xxx.php:
.htaccess
RewriteEngine on RewriteRule ^([a-zA-Z0-9_\-]{1,})\.manifest$ manifest/$1.php |
然后,我们要寻找一个可以自动更新的VERSION,我这里使用的时文件更新时间,对,寻找所有缓存文件中最晚修改过的那个文件的更新时间,然后将可能需要缓存的文件列表打印出来
index.html
<!DOCTYPE HTML> <html manifest="/test.manifest"> <head> <meta charset="UTF-8"> <title>manifest测试</title> <link rel='stylesheet' href='/css/test.css' /> <link rel='stylesheet' href='/css/test2.css' /> <script type='text/javascript' src='/js/test.js'></script> </head> <body> <img src="/img/test-pass-icon.png"></img> <hr> <img src="/img/btn_s.png"></img> <hr> <img src="/img/charts_images/dragIcon.gif"></img> <hr> <img src="/img/xx.png"></img> <hr> </body> </html> |
/test.manifest将会转到/manifest/test.php:
/manifest/test.php
<?php require_once 'manifestUtil.php'; //配置信息 $webroot = '../'; $urlroot = ''; //需要缓存的目录和文件(目录内的所有文件都将被输出) $sources = array( 'img', 'js/test.js', 'css', ); $updateTime = 0; $files = listFiles($sources, $updateTime, $webroot, $urlroot); ?> CACHE MANIFEST # version <?php echo $updateTime;?> CACHE: /index.html <?php echoFiles($files);?> NETWORK: * FALLBACK: |
manifestUtil.php
<?php //更具配置信息,读取文件列表 function listFiles($sources, &$updateTime, $webroot = '../', $url = ''){ $r = array(); foreach($sources as $s){ $r = array_merge($r, getFiles($webroot.'/'.$s, $updateTime, $url.'/'.$s)); } return $r; } //读取文件列表 //$types,需要缓存的文件类型 function getFiles($fileName, &$updateTime = 0, $url = '', $levels = 100, $types = array('jpg', 'png', 'gif', 'jpeg', 'css', 'js')){ if(empty($fileName) || !$levels){ return false; } $files = array(); if(is_file($fileName)){ $updateTime = getMax(filectime($fileName), $updateTime); $files[] = $url; }else if($dir = @opendir($fileName)){ while(($file = readdir($dir)) !== false){ if(in_array($file, array('.', '..'))) continue; if(is_dir($fileName.'/'.$file)){ $files2 = getFiles($fileName.'/'.$file, $updateTime, $url.'/'.$file, $levels - 1); if($files2){ $files = array_merge($files, $files2); } }else{ $updateTime = getMax(filectime($fileName.'/'.$file), $updateTime); $type = end(explode(".", $file)); if(in_array($type, $types)){ $files[] = $url.'/'.$file; } } } } @closedir($dir); // echo date("Y-m-d H:i:s",$updateTime).'<hr>'; return $files; } //打印缓存文件列表 function echoFiles($files){ for($i = 0; $i < count($files); $i++){ echo $files[$i].' ';//后面加一个换行 } } //取较大的更新时间 function getMax($a, $b){ return $a < $b ? $b : $a; } |
over~~~就是这些,下面的可能出现的问题:
这个只是初级方案,对于动态网页还有问题,比如,你请求不是静态的html,而是动态的php,而这个php里有require了其他的php,如果这些php发生了修改,上面的方案时不知道的,生成的manifest不会发生变化,这里就需要对方案做一个升级:除$sources之外,再加一个,比如$aboutSources,来配置其他相关文件,拿$aboutSources再调一次listFiles,综合$sources与$aboutSources的updateTime生成VERSION值
另外一个问题是,遍历相关文件,需要多次磁盘IO,如果文件太多,也会消耗较多的时间~~~凡事有利必有弊,如果对此不满,可以手动配置一个VERSION,每次修改后,更新VERSION值
—————
本文为本人原创,转载请注明出处
github:https://github.com/jklgithub/auto_manifest.git
参考:青梅煮酒-HTML5 离线存储实战之manifest