更新数据原理,访问接口,将服务器数据抓取并下载到本地的临时文件夹,当所有下载完成,卸载客户端内容,出现升级界面,此时移动下载的内容到目标文件夹,移动完成再重新加载客户端,访问接口,下载文件,移动文件均是队列完成。
根据实际接口操作可替换源代码中的必要代码,以下是源码:
DownloadControl.as
package com.controls { import com.controls.download.ConnectionUtil; import com.controls.download.DownloadFile; import com.controls.download.FileManager; import com.models.Config; import com.models.events.AppEvent; import com.models.events.AppEventDispatcher; import flash.filesystem.File; import flash.filesystem.FileMode; import flash.filesystem.FileStream; import flash.net.URLVariables; import flash.utils.ByteArray; /** * @author Frost.Yen * @E-mail 871979853@qq.com * @create 2017-2-20 下午4:19:33 * */ public class DownloadControl { /** * 下载资源的计数器 */ private var _count:uint; /** * 第一级接口个数计数器 */ private var _firstCount:int; /** * 第二级接口个数计数器 */ private var _secondCount:int; /** * 第一级接口返回的数据,供第二级接口递归调用 */ private var _datas:Object; private static var _instance:DownloadControl; public function DownloadControl(s:S) { } public static function getInstance():DownloadControl { if(!_instance){ _instance = new DownloadControl(new S()); } return _instance; } public function reset():void { _count = 0; _firstCount = 0; _secondCount = 0; _datas = null; Config.downloadData = []; } /** * 一级接口请求 */ public function connection1():void { var connection:ConnectionUtil = new ConnectionUtil(); connection.connect(Config.connection+Config.config.link.item[_firstCount].@typeLink,Config.config.link.item[_firstCount].@name+".json","",null,onConnectComplete); } /** * 二级接口请求 */ private function connection2(datas:Object):void { var total:int = datas["data"]["response"].length; var variables:URLVariables = new URLVariables(); variables.parameter = datas["data"]["response"][_secondCount]["id"]; var connection:ConnectionUtil = new ConnectionUtil(); connection.connect(Config.connection+Config.config.link.item[_firstCount].@contentLink,Config.config.link.item[_firstCount]+"_"+_secondCount+".json","",variables,onConnectComplete1); function onConnectComplete1(data:Object):void { for(var i:int = 0;i<data["data"]["response"].length;i++){ if(data["data"]["response"][i]["videoUrl"]){ var label:String = "videoUrl"; } if(data["data"]["response"][i]["imgUrl"]){ label = "imgUrl"; } var len:int = data["data"]["response"][i][label].length; for(var j:int = 0;j<len;j++){//存储下载的文件名称 Config.downloadData.push(data["data"]["response"][i][label][j]["openFile"]); if(label == "videoUrl"){ Config.downloadData.push(data["data"]["response"][i][label][j]["vframe"]); } } } Config.jsonArr[_firstCount][_secondCount]["second"] = data["data"]["response"];//二级菜单保存 _secondCount++; trace("------>>"+_secondCount+"------"+total+"-- "); if(_secondCount >= total){ _firstCount++; if(_firstCount>Config.config.link.item.length()-1){ //所有接口请求完成,将json保存到本地 var file:File = new File(Config.jsonPath+"data.json"); var fs:FileStream = new FileStream(); fs.open(file,FileMode.WRITE); fs.writeBytes(getByteArr(JSON.stringify(Config.jsonArr))); fs.close(); file = null; fs = null; //所有接口请求完成,开始下载 trace("------>>所有接口请求完成,开始下载---资源共:"+Config.downloadData.length+"个----- "); startDownload(); }else{ connection1(); } }else{ connection2(_datas); } } } private function onConnectComplete(data:Object):void { trace(JSON.stringify(data)); _datas = data; _secondCount=0; Config.jsonArr[_firstCount] = data["data"]["response"];//一级菜单保存 connection2(data); } /** * 开始下载 * @param isAll true表示所有资源同时下载 false表示资源队列下载 */ private function startDownload(isAll:Boolean=true):void { if(isAll){ for(var i:int = 0;i<Config.downloadData.length;i++){ download(i); } }else{ download(_count); } function download(i:int):void { new DownloadFile().download(Config.source,Config.downloadData[i],Config.tempPath,Config.assets,onDownloaded); } function onDownloaded():void { trace("------>>第"+_count+"个资源下载完成 "); _count++; if(_count == Config.downloadData.length){//Config.downloadData.length trace("------>>所有资源下载完成--------"); var tempList:Array = new File(Config.tempPath).getDirectoryListing(); AppEventDispatcher.getInstance().dispatchEvent(new AppEvent(AppEvent.DOWNLOAD_COMPLETE,tempList.length)); }else{ if(!isAll){ download(_count); } } } } public function startMove():void { FileManager.deleteFilesByNotSame(Config.downloadData,Config.assets); FileManager.startMoveFiles(File.applicationDirectory.nativePath+"/source/",Config.assets,onMoveComplete); } private function onMoveComplete():void { trace("------>>所有资源移动完成-------- "); AppEventDispatcher.getInstance().dispatchEvent(new AppEvent(AppEvent.UPDATE_COMPLETE)); } /** * 将String转换成ByteArray类型 * @param param 被转换的String * @return ByteArray 转换后的ByteArray * */ private function getByteArr(param:String):ByteArray { var bytes:ByteArray = new ByteArray; bytes.writeUTFBytes(param); return bytes; } } } class S{ }
接口连接工具类 ConnectionUtil.as
package com.controls.download { import flash.events.Event; import flash.events.EventDispatcher; import flash.events.IOErrorEvent; import flash.filesystem.File; import flash.filesystem.FileMode; import flash.filesystem.FileStream; import flash.net.URLLoader; import flash.net.URLRequest; import flash.net.URLRequestMethod; import flash.net.URLVariables; import flash.utils.ByteArray; /** * 连接接口工具类 * @author Frost.Yen * @E-mail 871979853@qq.com * @create 2017-2-16 下午2:50:58 * */ public class ConnectionUtil extends EventDispatcher { private var _ldr:URLLoader; /** * 将返回数据写入到本地,此为本地存储路径 */ private var _localPath:String; /** * 将返回数据写入到本地,此为文件名称 */ private var _fileName:String; /** * 接口连接地址 */ private var _connectionURL:String; /** * 接口所需参数 */ private var _argument:String; /** * 从接口获取的数据 */ public var data:Object; /** * 接口连接成功,获取数据后回调函数 */ public var onConnectSucceed:Function=null; public function ConnectionUtil() { _ldr = new URLLoader(); _ldr.addEventListener(Event.COMPLETE,onConnectComplete); _ldr.addEventListener(IOErrorEvent.IO_ERROR,onError); } /** * 连接接口成功 */ private function onConnectComplete(e:Event):void { var str:String = e.target.data; data = JSON.parse(str); trace(" <<----------------- aticon: "+_connectionURL+" ----------------- argument: "+_argument+" -------------------------->> result: "+str); if(data.code == "200"){ //将json写入本地 /*var file:File = new File(_localPath+_fileName); var fs:FileStream = new FileStream(); fs.open(file,FileMode.WRITE); fs.writeBytes(getByteArr(str)); fs.close(); file = null; fs = null;*/ if(onConnectSucceed!=null) onConnectSucceed(data); } } private function onError(e:IOErrorEvent):void { trace("error:"+e.text); } /** * 访问接口,获取数据 * @param connectPath:接口地址 * @param path : 将接口返回的json写入本地,此为本地地址 */ public function connect(connectPath:String,fileName:String,localPath:String="",argument:URLVariables=null,callback:Function=null,who:String=""):void { _connectionURL = connectPath; _fileName = fileName; localPath ==""?_localPath = File.applicationDirectory.nativePath+"/json/": _localPath = localPath; trace("接口地址:"+connectPath); var request:URLRequest = new URLRequest(connectPath); request.method = URLRequestMethod.POST; if(argument){ request.data = argument; _argument = argument.parameter; }else{ _argument = "无参数"; } _ldr.load(request); if(callback!=null) onConnectSucceed = callback; } /** * 将String转换成ByteArray类型 * @param param 被转换的String * @return ByteArray 转换后的ByteArray * */ private function getByteArr(param:String):ByteArray { var bytes:ByteArray = new ByteArray; bytes.writeUTFBytes(param); return bytes; } } }
下载文件类 DownloadFile.as
package com.controls.download { import com.models.Config; import flash.events.Event; import flash.events.EventDispatcher; import flash.events.IOErrorEvent; import flash.events.ProgressEvent; import flash.filesystem.File; import flash.filesystem.FileMode; import flash.filesystem.FileStream; import flash.net.URLLoader; import flash.net.URLLoaderDataFormat; import flash.net.URLRequest; import flash.net.URLRequestHeader; import flash.utils.ByteArray; /** * 下载文件工具类 * @author Frost.Yen * @E-mail 871979853@qq.com * @create 2017-2-16 下午12:55:22 * */ public class DownloadFile extends EventDispatcher { private var _downloadLoader:URLLoader; /** * 是否下载完成标识 */ private var _downloadEnd:Boolean; private var _startPoint:uint = 0; private var _endPoint:uint = 0; private var _total:uint = 0; /** * 文件名(xx.jpg,xx.flv) */ private var _fileName:String; /** * 下载时保存的临时路径,下载完成后需要从这个地址移动到程序访问的路径 */ private var _tempPath:String = ""; /** * 程序访问资源的本地路径 */ private var _localPath:String = ""; /** * 服务端抓取数据的路径 */ private var _remotePath:String = ""; /** * 下载完成回调函数 */ private var _downloadComplete:Function; public function DownloadFile() { init(); } private function init():void { _downloadLoader = new URLLoader(); _downloadLoader.dataFormat = URLLoaderDataFormat.BINARY; _downloadLoader.addEventListener(Event.COMPLETE,onLoaded); _downloadLoader.addEventListener(IOErrorEvent.IO_ERROR,onError); } private function onLoaded(e:Event):void { if(e.target.data.length == 0){ writeBytes(_tempPath,e.target.data,0,e.target.data.length); this.dispatchEvent(new Event(Event.COMPLETE)); if(_downloadComplete!=null) _downloadComplete(); }else{ if(_downloadEnd){ _startPoint = _endPoint; writeBytes(_tempPath,e.target.data,0,e.target.data.length); this.dispatchEvent(new Event(Event.COMPLETE)); if(_downloadComplete!=null) _downloadComplete(); }else{ _startPoint = _endPoint; writeBytes(_tempPath,e.target.data,0,e.target.data.length-1); stepDownload(); } } } /** * 将数据写入到本地,即下载 * @param path 本地保存地址 * @param bytes 要写入的字节数组。 * @param offset 从零开始的索引,指定在数组中开始写入的位置。 * @paramlength 一个无符号整数,指定在缓冲区中的写入范围。 */ private function writeBytes(path:String,bytes:ByteArray, offset:uint=0, length:uint=0):void { var file:File = new File(path+_fileName); var fs:FileStream = new FileStream();; fs.open(file,FileMode.UPDATE); fs.position = fs.bytesAvailable;//将指针指向文件尾 fs.writeBytes(bytes,offset,length);//在文件中写入新下载的数据 fs.close(); } /** * 分步下载 */ private function stepDownload():void { _endPoint += 10000000; if(_endPoint > _total ){ _endPoint = _total; _downloadEnd = true; } var request:URLRequest = new URLRequest(_remotePath+_fileName); var header:URLRequestHeader = new URLRequestHeader("Range","bytes="+_startPoint+"-"+_endPoint); request.requestHeaders.push(header); _downloadLoader.load(request); } /** * 开始下载文件 * @param remoteURL 数据存放的远程地址 * @param fileName 下载的文件名 * @param tempPath 下载保存到本地的临时目录 * @param localPath 最终程序访问的本地目录 */ public function download(remotePath:String,fileName:String,tempPath:String,localPath:String,callback:Function=null):void { _remotePath = remotePath; _fileName = fileName; _tempPath = tempPath; _localPath = localPath; _downloadComplete = callback; _downloadEnd = false; _startPoint = 0; _endPoint = 0; var file:File = new File(_localPath+_fileName); if(file.exists){//假如存在此文件,就不下载,跳过 this.dispatchEvent(new Event(Event.COMPLETE));//可以回调,可以派发 if(_downloadComplete!=null) _downloadComplete(); }else{ _downloadLoader.addEventListener(ProgressEvent.PROGRESS,onProgress); _downloadLoader.addEventListener(IOErrorEvent.IO_ERROR,onError); try { _downloadLoader.load(new URLRequest(_remotePath+_fileName)); } catch(error:Error) { trace(error.message); } } } private function onProgress(e:ProgressEvent):void { _total = _downloadLoader.bytesTotal; _downloadLoader.removeEventListener(ProgressEvent.PROGRESS,onProgress); _downloadLoader.close(); stepDownload(); } private function onError(e:IOErrorEvent):void { trace(e.text); //错误时跳过,继续下一个下载 if(_downloadComplete!=null) _downloadComplete(); } /** * 释放下载工具 */ public function dispose():void { _downloadLoader.removeEventListener(Event.COMPLETE,onLoaded); _downloadLoader.removeEventListener(IOErrorEvent.IO_ERROR,onError); _downloadLoader.removeEventListener(ProgressEvent.PROGRESS,onProgress); _downloadLoader.close(); _downloadLoader = null; } } }
文件操作类 FileManager.as
package com.controls.download { import flash.events.Event; import flash.filesystem.File; /** * 文件操作类 * @author Frost.Yen * @E-mail 871979853@qq.com * @create 2017-2-20 上午11:34:16 * */ public class FileManager { private static var _moveCount:int; private static var _moveComplete:Function; private static var _targetDir:String; private static var _tempDir:String; private static var _templist:Array; public function FileManager() { } public static function reset():void { _moveCount = 0; _templist = null; } /** * 在目标目录下删除数组中不存在的文件 * @param filesName 文件名数组 * @param targetDir 目标文件夹 */ public static function deleteFilesByNotSame(filesName:Array,targetDir:String):void { var targetList:Array = new File(targetDir).getDirectoryListing(); for(var i:int;i<targetList.length;i++){ if(filesName.indexOf(targetList[i].name)==-1){ (targetList[i] as File).deleteFile(); trace("删除文件:"+(targetList[i] as File).nativePath+" "); } } } /** * 开始移动文件 * @param tempDir 存储下载文件的临时目录 * @param targetDir 需要移动到的目标目录 * @callba 移动完成,回调函数 */ public static function startMoveFiles(tempDir:String,targetDir:String,callback:Function):void { _moveCount = 0; _targetDir = targetDir; _tempDir = tempDir; _moveComplete = callback; _templist = new File(_tempDir).getDirectoryListing(); if(_templist.length){ moveFiles(); }else{ _moveComplete(); } } /** * 移动文件 */ private static function moveFiles():void { var fromFile:File = new File(_tempDir+_templist[_moveCount].name); var toFile:File = new File(_targetDir+_templist[_moveCount].name); trace("移动文件:"+_moveCount+"个-->>"+_templist[_moveCount].name); trace(_tempDir+_templist[_moveCount].name,_targetDir+_templist[_moveCount].name); fromFile.moveToAsync(toFile,true); fromFile.addEventListener(Event.COMPLETE,onFileMoveComplete); } private static function onFileMoveComplete(e:Event):void { _moveCount++; if(_moveCount>_templist.length-1){ //全部移动完成 _moveComplete(); }else{ moveFiles(); } } } }
还有个数据存储类 Config.as
package com.models { import flash.filesystem.File; /** * * @author Frost.Yen * @E-mail 871979853@qq.com * @create 2017-2-16 下午1:35:43 * */ public class Config { public static var config:XML; /** * 服务器连接地址 */ public static var connection:String; /** * 远程资源地址 cdn */ public static var source:String; /** * 本地资源地址 */ public static var assets:String; /** * 存储所有下载资源的信息(目前仅存文件名称) */ public static var downloadData:Array = []; /** * 写入到本地的json目录地址 */ public static var jsonPath:String = File.applicationDirectory.nativePath+"/data/"; /** * 下载资源的临时存放目录 */ public static var tempPath:String = File.applicationDirectory.nativePath+"/source/"; /** * 接口返回的json数据组合 */ public static var jsonArr:Array = []; public function Config() { } } }
若要为己所用,据具体需求请改代码。