更新文件避免浏览器缓存的解决方法(源码)

上次说的:更新文件避免浏览器缓存的解决方案(基于svn)(好纠结的名字啊……),方案测试一段时间之后,没什么太大的问题。共享之。

表述得很不清楚,总之这个东东要实现的目的是:当把项目的新版本放到IIS服务器上之后,保证客户端浏览器Flash再加载的是最新文件,而不是傻呼呼的让用户去清缓存—_—。总的思路是:利用svn的每次提交都会为文件记录一个版本号,我们让程序在加载文件时url都增加一个文件的svn版本参数(例如:http://…/test.jpg?v=3393)。

流程下如下图,我们用mFileRevisionManager来管理文件的版本号。

当然,这就得要求项目程序代码在加载资源使用统一得接口:mFileRevisionManager,比如要加载一份xml文件,代码类似这样:

var xmlLoader:URLLoader = new URLLoader();
var req:URLRequest = mFileRevisionManager.getFileUrlRequest("data/test.xml");
xmlLoader.load(req);

mFileRevisionManager的初始化应该放在最开始的地方,这样我们需要给主程序(main.swf)添加一个预载(preload.swf),这个预载会加载资源的版本信息文件(revision.txt),初始化mFileRevisionManager。如下图:

这个解决方案的使用的开发环境是:FDT 4 + SVN + Flash IDE

需要安装Subversion,这样我们在ant脚本中可以直接执行svn命令。

所有的源码打包:
下载

解压缩包会得到msc、tool两个文件夹。msc文件夹下是AS3代码文件。tool文件夹下包括一个ant脚本和一份jsfl脚本。

  1. Flash端AS3代码

    AS3部分核心类是mPreloadermFileRevisionManagermPreloader是整个程序的预载器,负责加载svn版本号信息文件(cur.txt、revision.txt),然后初始化mFileRevisionManager。实际使用时,把mPreloader编译出一个swf,比如preload.swf。如果你没有修改mPreloader.as的话,preload.swf会加载load.swf,当然你也可以修改成main.swf、game.swf、……

  2. ANT脚本:发布.xml

    假设bin是整个Flash项目最终输出(要发布的)文件夹。

    这个ANT脚本的执行流程是:

    • 提交bin文件夹下的所有修改到svn服务器上。
    • 导出bin目录下所有文件的svn信息,以XML文件形式保存(revision.xml)。把当前的版本号写入cur.txt中。
    • Flash执行jsfl脚本,压缩生成的信息文件(revision.xml),保存成revision.txt
    • 提交cur.txt、revision.txt到svn服务器中。
  3. 一点点修改

    把ant脚本中的Flash.exe路径修改成你电脑上的Flash路径。jsfl脚本第一行的revXmlUri修改成要压缩的revision.xml的路径。
    基本上你在发布整个项目时运行下ant脚本就可以了。

更新文件避免浏览器缓存的解决方案(基于svn)

问题的存在

一旦项目上线,隔不久发布更新,就会碰到一个问题:如何保证客户端(Flash)加载到的是最新的文件,而不是浏览器中的缓存?

问题的解决

最基本的,想让as3加载文件时忽略浏览器缓存可以是

  • 在URLRequestHeader中添加”no-cache”
  • 在URLRequest中附带一个参数

但显然如果文件在没有发布新版本的情况下,用不着让文件每次加载都忽略浏览器缓存,太浪费了。

那么只要有份数据,列表记录此次发布修改过的文件,让客户端(Flash)每次运行时都加载该列表。当需要加载某个文件时,可以比较这个列表,看是否需要忽略浏览器缓存加载最新文件。

这个机制挺ok的,但是如果客户端错过了一个版本,那么就可能会仍然存在没使用最新文件的问题,如图:

客户端错过了1.0.1版本的发布,没有更新“…/…/1.jpg”和“…/…/2.jpg”,当更新到1.0.3版本时,因为1.0.3版本没有记录“…/…/1.jpg”和“…/…/2.jpg”的修改,所以客户端会从浏览器缓存中加载使用这两个文件最早的版本。

可以看出,只记录更新文件(modified files)的方法不能“安全”地解决这个问题。

为安全解决这个问题,完全可以利用svn,生成一个数据文件,该数据记录每一次发布时每个文件的版本号。在客户端(Flash)运行时,因为每个文件都有个版本号,只要比较服务器与浏览器缓存中的记录文件版本号,即可决定是否忽略浏览器缓存加载最新文件。

如图,客户端(Flash)首先把浏览器缓存中的版本文件和服务器上最新的版本文件都加载进来,一旦运行时需要加载某个文件时,先比较两个版本号是否相同,如果不同则加载服务器上的文件。

动手吧

生成svn status文件

在项目新版本完成,提交到svn时,可以利用svn的命令行工具,把svn status信息输出到xml文件中,供Flash AS3读取解析。svn输出status的信息的命令是:

svn status --xml >> revisions.xml

不过svn status输出产生的xml文件非常详细,文件占得空间较大,作为每次客户端(Flash)运行都需要加载的文件,必需进行压缩。

客户端(Flash)AS3的工作

AS3方面可以编写一个类似RevisionManager的管理类,用来担起各个文件版本管理、比较的重任。

让一切自动化

最后,需要编写一个用于发布的ant脚本,这个ant应该能够:

  1. 利用svn命令行工具输出svn status信息文件
  2. 把版本信息文件进行压缩,这个可以利用JSFL来实现(Flash CS3后JSFL开始更新到E4X 2标准,支持XML)
  3. 把项目新版本提交到svn
  4. 每次发布只要运行下这个ant build.xml即可啦。

最终实现

请参考:更新文件避免浏览器缓存的解决方法(源码)

JSFL取得当前编辑项的方法

之前写过一个JSFL脚本用于图片的9格打散(scale9Grid),一直找不到取得“当前编辑项”的方法,无奈之下就用了:

fl.getDocumentDOM().library.getSelectedItems();

也就是必须,在库中选中这个项才能运行这个JSFL
不过gskinner也实现了个同样功能的脚本,我才发现可以通过时间轴名字取得“当前编辑项”:

doc.library.items[doc.library.findItemIndex(doc.getTimeline().name)];

把图形替换成图片的脚本

把图形替换成图片的脚本,graphics2bmp

graphics2bmp.jsfl这个脚本的目的是:把你在Flash上选中的元素替换成图片!有次美工给了一个界面,里面使用了很多(貌似是)娃娃字体的文本,问题是开发的这个游戏项目中,是把Flash Player的影片质量设为“低”的,如此设置下,这些可爱的娃娃字体在实际swf中就会有锯齿,变得很挫。

当然,可以继续让美工把这些文字,单独导成图片,再导入到Flash中进行替换。而graphics2bmp.jsfl可以帮你进行这些繁琐的操作!

使用举例:新建个fla文件,保存一下,随便画个图形,选中这个图形,然后,双击graphics2bmp.jsfl运行脚本,你会看到你刚才选中的东东已经被替换成图片了。

graphics2bmp.jsfl

9格切片位图脚本

Flash的9切片缩放(scale9Grid)对位图是没有效果的,在Flash IDE下,可以把位图的9格区域分别打散来实现。如此繁琐的操作当然最好让jsfl来做了,于是tamt编写了这个小脚本:)

使用的话:

  1. 在库面板中,把含有图片的影片剪辑的“启用9切片比例缩放辅助线”勾上。
  2. 进入这个影片剪辑的编辑状态,选中图片。
  3. 执行“[t]9格切片位图.jsfl”脚本,完成。

[t]9格切片位图.jsfl

在AS3环境下,可以通过著名的ScaleBitmap来实现。

[2010.04.17更新]gksinner也实现了同样的一个脚本,推荐使用^_^