首先介绍下自己的思路:现在air都分模块化的,所以也是分模块进行更新,外加程序进行更新,
就是从远程download下载swf然后替换本地的,程序更新是先down下来,然后使用自带的updater进行更新
说实在的我的flex有时候也弄不懂,有时候改了一个地方,不知道编译器会更改哪里,更新要先测试,是不是指更改了这一个模块;
好了上代码,首先是模块更新
package com.fileOperations { public class FileModuleUpdate extends Sprite { public function FileModuleUpdate() { } /** * 需要更新的数量 * */ private var swfCount:Number = 0; /** * 已经更新的数量 * */ private var updatedCount:Number = 0; private var newVersionXML:XML; /** * 获取新的配置文件 * */ public function getNewFileVersionConfigXMl(url:String):void{ swfCount = 0; updatedCount = 0; var loadUrl:URLLoader = new URLLoader(); loadUrl.load(new URLRequest(url)); loadUrl.addEventListener(Event.COMPLETE,checkIsUpdated); } private var url:String;//地址 private var _description:String;//升级描述 /** * 检查这个文件是不是需要更新,由总的文件版本号确定 * */ private function checkIsUpdated(event:Event):void{ var loader:URLLoader = URLLoader(event.target); var xml:XML = XML(loader.data); newVersionXML = xml; var object:XML; for(var i:int = 0;i<xml.children().length();i++){ object = xml.children()[i] as XML; var id:String = object.attribute("id"); if(id == "v_main"){ var version:String = (object.children()[0] as XML).@['value']; var dic :Dictionary = IocAppFacade.getInstance().getObject("v_main") as Dictionary; if(getIsHideVersion(dic,version)){ url = (object.children()[1] as XML).@['value']; description = (object.children()[2] as XML).@['value']; dispatchEvent(new FileUpdateEvent(FileUpdateEvent.FILE_HAVE_UPDATE,xml)); }else{ dispatchEvent(new FileUpdateEvent(FileUpdateEvent.NOT_FILE_HAVE_UPDATE)); } break; } } loader.close(); } public function updateFileMoudle(xml:XML):void{ updateThisSystem(xml); } /** * 判断版本号的大小 * */ private function getIsHideVersion(dic:Dictionary,version:String):Boolean{ if(dic==null||version.length==0){return false;} var local:Number = Number((dic['version'] as String).replace(".","")); var online:Number = Number(version.replace(".","")); return online>local; } /** * 检查这个文件是不是需要更新 * */ private function updateThisSystem(xml:XML):void{ var object:XML; var id:String; var version:String; var palce:String; for(var i:int = 2;i<xml.children().length();i++){ object = xml.children()[i] as XML; id = object.attribute("id"); version= (object.children()[0] as XML).@['value']; palce= (object.children()[1] as XML).@['value']; var dic :Dictionary = IocAppFacade.getInstance().getObject(id) as Dictionary; if(dic==null||getIsHideVersion(dic,version)){ swfCount++; if(palce.lastIndexOf("swf")!=-1){ updateThisModule(palce); }else{ updateThisConfig(palce); } } } } private function updateThisConfig(path:String):void{ var loadUrl:URLLoader = new URLLoader(); loadUrl.load(new URLRequest(url+path)); loadUrl.addEventListener(Event.COMPLETE,function():void{ var xml:XML = XML(loadUrl.data); saveXML(xml,path); swfUpdateSuccess(null); loadUrl.close(); }); } /** * 更新这个,模块 * */ private function updateThisModule(path:String):void{ var loadUrl:URLLoader = new URLLoader(); loadUrl.dataFormat = URLLoaderDataFormat.BINARY; loadUrl.load(new URLRequest(url+path)); loadUrl.addEventListener(Event.COMPLETE,function():void{ var stream:FileStream = new FileStream(); var fileName:String = getFileName(path); var file:File = new File(fileName); stream.openAsync(file, FileMode.UPDATE); stream.addEventListener(IOErrorEvent.IO_ERROR,function(e:IOErrorEvent):void{ swfUpdateSuccess(null); stream.close(); //这个是用来放置用户磁盘保护这样就会报错,所以会监视,关闭 }); stream.addEventListener(Event.CLOSE,swfUpdateSuccess); stream.writeBytes(loadUrl.data); stream.close(); loadUrl.close(); }); loadUrl.addEventListener(IOErrorEvent.IO_ERROR,function(e:IOErrorEvent):void{ swfUpdateSuccess(null); trace(e.toString()+"--------------流错误"); loadUrl.close(); }); } private function swfUpdateSuccess(e:Event):void{ updatedCount++; var percentage:Number = Math.floor(updatedCount*100/swfCount); dispatchEvent(new FileUpdateEvent(FileUpdateEvent.UPDATE_PERCENTAGE,percentage)); if(updatedCount == swfCount){ dispatchEvent(new FileUpdateEvent(FileUpdateEvent.UPDATE_COMPLETE)); saveXML(newVersionXML,"更新文件XML名"); } } /** * 对xml文件进行存储 * */ private function saveXML(xml:XML,name:String):void{ var xmlOperation:ConfigXmlOperation = new ConfigXmlOperation(); xmlOperation.fileName = File.applicationDirectory.resolvePath(name).nativePath; xmlOperation.writeConfigXml(xml); } /** * 获取文件的真是路径 * */ private function getFileName(path:String):String{ var fileName:String = File.applicationDirectory.resolvePath("根目录的一个文件名").nativePath; fileName = fileName.substring(0,fileName.indexOf("根目录的一个文件名")); return fileName += path; } public function get description():String{ return _description; } public function set description(value:String):void{ _description = value; } } }
然后是air文件更新代码:
package com.copote.fileOperations { public class AirFileUpdate extends Sprite { public function AirFileUpdate() { } /** * 文件的地址 * */ private var url:String; /** * 文件的版本号 * */ private var newVersion:String; public function checkMainAirIsNeedUpdate(xml:XML):void{ var object:XML; for(var i:int = 0;i<xml.children().length();i++){ object = xml.children()[i] as XML; var id:String = object.attribute("id"); if(id == "文件名"){ newVersion = (object.children()[0] as XML).@['value']; var dic:Dictionary = IocAppFacade.getInstance().getObject("文件名") as Dictionary; url = dic['palce']; dispatchEvent(new FileUpdateEvent(FileUpdateEvent.AIR_HAVE_UPDATE,getIsHideVersion(dic,newVersion))); break; } } } /** * 判断版本号的大小 * */ private function getIsHideVersion(dic:Dictionary,version:String):Boolean{ var local:Number = Number((dic['version'] as String).replace(".","")); var online:Number = Number(version.replace(".","")); return online>local; } public function updateAIR():void{ var file:File = new File(fileName); var loadUrl:URLLoader = new URLLoader(); loadUrl.dataFormat = URLLoaderDataFormat.BINARY; loadUrl.load(new URLRequest(url)); loadUrl.addEventListener(ProgressEvent.PROGRESS,getLoadProgress); loadUrl.addEventListener(Event.COMPLETE,function():void{ var stream:FileStream = new FileStream(); var file:File = new File(fileName); stream.openAsync(file, FileMode.UPDATE); stream.addEventListener(IOErrorEvent.IO_ERROR,function(e:IOErrorEvent):void{ stream.close(); //这个是用来放置用户磁盘保护这样就会报错,所以会监视,关闭 }); stream.addEventListener(Event.CLOSE,updateFile); stream.writeBytes(loadUrl.data); stream.close(); }); loadUrl.addEventListener(IOErrorEvent.IO_ERROR,function(e:IOErrorEvent):void{ trace(e.toString()+"--------------流错误"); loadUrl.close(); }); } private function get fileName():String{ var fileName:String = File.applicationDirectory.resolvePath("根目录的一个文件名").nativePath; fileName = fileName.substring(0,fileName.indexOf("根目录的一个文件名")); return fileName+"文件名"; } private function updateFile(event:Event):void{ var updater:Updater=new Updater ; var airFile:File= File.applicationDirectory.resolvePath("文件名"); updater.update(airFile,newVersion); } private function getLoadProgress(e:ProgressEvent):void{ var percentage:Number = Math.floor(e.bytesLoaded*100/e.bytesTotal); dispatchEvent(new FileUpdateEvent(FileUpdateEvent.UPDATE_PERCENTAGE,percentage)); } } }
更新中的事件
package com.copote.fileOperations.event { import flash.events.Event; public class FileUpdateEvent extends Event { /** * 文件升级 * */ public static const FILE_HAVE_UPDATE:String = "fileHaveUpdate"; /** * 文件升级 * */ public static const NOT_FILE_HAVE_UPDATE:String = "notFileHaveUpdate"; /** * 主程序升级 * */ public static const AIR_HAVE_UPDATE:String = "airFileHaveUpdate"; /** * 以加载的百分比 * */ public static const UPDATE_PERCENTAGE:String = "updatePercentage"; /** * 更新完成 * */ public static const UPDATE_COMPLETE:String = "updateComplete"; public var data:Object; public function FileUpdateEvent(type:String, mydata:Object =null, bubbles:Boolean = false, cancelable:Boolean = false) { super(type, bubbles,cancelable); data = mydata; } } }
界面就不写了,这里自己接触了流和文件读写,学习了下,配置文件时读取的xml
像这样子:
<object id="v_main" class="flash.utils.Dictionary"> <property name="version" value="0.3.6"></property> <property name="palce" value="连接文件的目录"></property> <property name="description" value="增加了一部分功能,修改了部分bug,对一些界面做了美化"></property> </object>
本地配置文件使用spring来读取的
存在的问题是,如果要更新就要对每一个模块写配置,比较麻烦