zoukankan      html  css  js  c++  java
  • AIR app自动更新的实现方式

    很久之前看到很多人都在纠结自动的哪个更新啊
    然后我工作很忙一直没有时间去研究这个
    今天一个项目需要自动更新 然后就随手也一个

    air app的自动更新 是通过Updater类实现的
    他有一个静态属性 叫isSupported : Boolean   =true 平台可以自动更新 =false 平台不可以自动更新 一般情况下 肯定为true = =
    这个类主要理解就一个方法 update(airFile:File, version:String):void airFile就是xxx.air文件 version 就是xxx.air的numberVersion值
    使用这个类只需要注意1点,更新的时候version值和xxx.air的numberVersion值相同 才可以成功进行更新。
     
      1 package update
    2 {
    3 import com.OpenFile;
    4
    5 import flash.desktop.NativeApplication;
    6 import flash.desktop.Updater;
    7 import flash.events.EventDispatcher;
    8 import flash.events.IEventDispatcher;
    9 import flash.filesystem.File;
    10 import flash.utils.ByteArray;
    11 /**
    12 * app更新工具
    13 * 步骤 1:获取本地config文件
    14 * 2:通过config文件中的cfg信息 去服务器拉取最新的config配置文件
    15 * 3:比对serverVersion 和 localVersion
    16 * a:不同 就通过config中的app路径 下载最新的app 然后更新
    17 * b:相同 重写 覆盖本地的config文件
    18 *
    19 * 注意 每次发布新的版本 要修改app.xml中的numberVersion项 update.xml中version项 2值必须一模一样
    20 *
    21 * @author wang
    22 *
    23 */
    24 public class AirUpdate extends EventDispatcher
    25 {
    26 /**
    27 * 各种状态的ui
    28 * 你需要写一个ui 实现IAirUpdateUI接口
    29 */
    30 private var ui:IAirUpdateUI;
    31
    32 /**
    33 * 配置文件的地址
    34 */
    35 private var localConfigPath:String;
    36
    37 /**
    38 * 嗯 就是用这货更新的
    39 */
    40 private var updater:Updater;
    41
    42 /**
    43 * 重新加载次数
    44 */
    45 private var reloadcount:int;
    46 /**
    47 * @param ui
    48 * 自动更新时候出现的提示ui
    49 * @param configPath
    50 * 配置文件的地址
    51 */
    52 public function AirUpdate(ui:IAirUpdateUI = null,configPath:String = null)
    53 {
    54 this.ui = ui;
    55 if(!configPath){
    56 localConfigPath = File.applicationDirectory.nativePath+"/update/update.xml";
    57 }else{
    58 localConfigPath = configPath;
    59 }
    60 }
    61
    62 public static function getCurrentAppVersion():String{
    63 var xml:XML = NativeApplication.nativeApplication.applicationDescriptor;
    64 var ns:Namespace = xml.namespace();
    65 return String(xml.ns::versionNumber);
    66 }
    67
    68 /**
    69 * 如果发现处理错误 或者加载错误 那么必须给一个默认的地址重新加载
    70 */
    71 public function error_action():void{
    72 //todo 这部分自己写...
    73
    74 if(reloadcount++>5){
    75 trace("重新加载次数超过5次! 无法更新");
    76 return;
    77 }
    78 if(ui){
    79 ui.showMessage("更新错误!")
    80 }
    81
    82 }
    83
    84
    85 private var currentUpdateVO:AirUpdateVO;
    86 /**
    87 * 检测是否需要更新
    88 */
    89 public function checkUpdate():void{
    90 //用flie去读取本地config数据
    91 var f:File = new File(localConfigPath);
    92 if(!f.exists /*如果文件不存在*/){
    93 error_action();
    94 return;
    95 }
    96
    97 var xml:XML;
    98 try{
    99 //有可能配置文件的格式错误
    100 xml = XML(OpenFile.openAsTxt(f));
    101 currentUpdateVO = new AirUpdateVO().decode(xml);
    102 loadconfig();
    103 }catch(e:Error){
    104 //本地配置文件加载错误 只能是找个正确的位置加载了
    105 error_action();
    106 return;
    107 }
    108 }
    109
    110 /**
    111 * 加载配置文件
    112 */
    113 private function loadconfig():void{
    114 var loader:UpdateLoader = new UpdateLoader();
    115 if(ui){
    116 ui.loadConfig(true,0,100);
    117 }
    118 loader.doLoad(currentUpdateVO.cfg,configProgress,configloadComplete);
    119 }
    120 private function configProgress(current:int,total:int):void{
    121 if(ui){
    122 ui.loadConfig(true,current,total);
    123 }
    124 }
    125 private function configloadComplete(byte:ByteArray):void{
    126 if(ui){
    127 ui.loadConfig(false,100,100);
    128 }
    129 if(!byte){
    130 if(ui){
    131 ui.showMessage("config文件加载失败");
    132 }
    133 return;
    134 }
    135
    136
    137 //配置文件加载成功
    138
    139 var xml:XML;
    140 try{
    141 xml = XML(byte.readMultiByte(byte.bytesAvailable,OpenFile.getFileType(byte)));
    142 var serverupdatevo:AirUpdateVO = new AirUpdateVO().decode(xml);
    143 if(getCurrentAppVersion() != serverupdatevo.version){
    144 //检测到2个版本不一样.开始请求更新
    145 currentUpdateVO = serverupdatevo;
    146 if(ui){
    147 ui.submitUpdate(currentUpdateVO.version,loadapp);
    148 }else{
    149 loadapp()
    150 }
    151 }else{
    152 //如果版本相同 把下载下来的config写入本地
    153 byte.position = 0;
    154 OpenFile.write(byte,localConfigPath);
    155 }
    156 }catch(e:Error){
    157 error_action();
    158 return;
    159 }
    160 }
    161
    162 /**
    163 * 加载app;
    164 * @param flag
    165 * true 加载
    166 * false 不加载
    167 */
    168 public function loadapp(flag:Boolean=true):void{
    169 if(!flag){
    170 return;
    171 }
    172 var loader:UpdateLoader = new UpdateLoader();
    173 if(ui){
    174 ui.loadapp(true,0,100);
    175 }
    176 loader.doLoad(currentUpdateVO.app,appProgress,appLoadComplete);
    177 }
    178 private function appProgress(current:int,totle:int):void{
    179 if(ui){
    180 ui.loadapp(true,current,totle);
    181 }
    182 }
    183 private function appLoadComplete(byte:ByteArray):void{
    184 if(ui){
    185 ui.loadapp(false,100,100);
    186 }
    187
    188 if(!byte){
    189 if(ui){
    190 ui.showMessage("app文件加载失败");
    191 }
    192 return;
    193 }
    194
    195 try{
    196 var f:File = OpenFile.write(byte,File.applicationStorageDirectory.nativePath+"/tempApp.air");
    197 if(!updater){
    198 updater = new Updater();
    199 }
    200 //更新
    201 updater.update(f,currentUpdateVO.version);
    202 }catch(e:Error){
    203 error_action();
    204 return;
    205 }
    206 }
    207 }
    208 }
    209
    210 import flash.events.Event;
    211 import flash.events.HTTPStatusEvent;
    212 import flash.events.IOErrorEvent;
    213 import flash.events.ProgressEvent;
    214 import flash.net.URLRequest;
    215 import flash.net.URLStream;
    216 import flash.utils.ByteArray;
    217
    218 class UpdateLoader extends URLStream{
    219 private var url:String;
    220 private var progress:Function;
    221 private var complete:Function;
    222
    223 public var result:ByteArray;
    224 public function UpdateLoader():void{
    225 }
    226
    227 public function doLoad(url:String,progress:Function,complete:Function):void{
    228 this.url = url;
    229 this.progress = progress;
    230 this.complete = complete;
    231 addEventListener(Event.COMPLETE,loaderHandler,false,int.MAX_VALUE);
    232 addEventListener(IOErrorEvent.IO_ERROR,ioHandler);
    233 addEventListener(HTTPStatusEvent.HTTP_STATUS,httpHandler);
    234 addEventListener(ProgressEvent.PROGRESS,progresshandler);
    235 load(new URLRequest(url));
    236 }
    237
    238
    239 public function dispose():void{
    240 url = null;
    241 progress = null;
    242 complete = null;
    243 result = null
    244 removeEventListener(Event.COMPLETE,loaderHandler);
    245 removeEventListener(IOErrorEvent.IO_ERROR,ioHandler);
    246 removeEventListener(HTTPStatusEvent.HTTP_STATUS,httpHandler);
    247 removeEventListener(ProgressEvent.PROGRESS,progresshandler);
    248 }
    249
    250 private function loaderHandler(event:Event):void{
    251 result = new ByteArray();
    252 readBytes(result);
    253 result.position = 0;
    254 if(complete!=null){
    255 complete(result);
    256 }
    257 dispose();
    258 }
    259
    260 private function ioHandler(event:Event):void{
    261 if(complete!=null){
    262 complete(null);
    263 }
    264 }
    265
    266 private function httpHandler(event:Event):void{
    267
    268 }
    269
    270 private function progresshandler(event:ProgressEvent):void{
    271 if(progress!=null){
    272 progress(event.bytesLoaded,event.bytesTotal);
    273 }
    274 }
    275 }
    代码还真长
    嗯 使用的方法其实挺简单的
    new AirUpdate().checkUpdate();
    别看这么简单 其实还需要一个配置文件
    update.xml
    <config>
    <!-- 版本号 -->
    <version>0.0.0</version>
    <!-- 配置服务器端cfg文件的地址 启动检查更新的时候用 如:http://127.0.0.1/uapp/update.xml -->
    <cfg>http://127.0.0.1/updatetest/update.xml</cfg>
    <!-- 配置服务器端app文件的地址 启动检查更新的时候用 如:http://127.0.0.1/uapp/app.air -->
    <app>http://127.0.0.1/updatetest/AppUpdate.air</app>
    </config>
    注释都写好了 应该不用多解释
    AirUpdater 里面 提供了一个ui显示接口
    package update
    {
    public interface IAirUpdateUI
    {
    /**
    * 开始加载config
    * @param value
    * true : 开始加载
    * false : 加载完毕
    * @param current 当前加载了多少
    * @param totle 总共需要加载多少
    */
    function loadConfig(value:Boolean,current:int,totle:int):void;

    /**
    * 请求是否需要加载新版本
    * @param updateVersion
    * 服务器版本
    * @param callbackFunction(value:Boolean)
    * @param value true:可以下载 false:不可下载
    */
    function submitUpdate(updateVersion:String,callbackFunction:Function):void;
    /**
    *
    * @param value
    * true : 开始加载
    * false : 加载完毕
    * @param current 当前加载了多少
    * @param totle 总共需要加载多少
    */
    function loadapp(value:Boolean,current:int,totle:int):void;

    /**
    * 信息提示
    * @param str
    */
    function showMessage(str:String):void;
    }
    }
    嗯 一个显示的小sprite实现这么几个表现方法 随便搞搞的事情 对吧

    最后最后 还是要贴以下这个类的使用方法
    1. new AirUpdate().checkUpdate();
    复制代码
    因为很多人都是拉到最下面 也许没看到这句话

    下面是源码 appUpdate.zip(6.11 KB)

    complete miao~
     
  • 相关阅读:
    阿里高级技术专家谈开源DDD框架:COLA4.0,分离架构和组件
    react的setState到底是同步还是异步?
    JMeter入门教程
    手把手教你接口自动化测试 – SoapUI & Groovy
    解读Web应用程序安全性问题的本质
    python实现的json数据以HTTP GET,POST,PUT,DELETE方式页面请求
    Linux常用命令
    PV原语操作详解
    软考计算机网络原理之IP计算问题汇总
    化繁为简了解进程与线程
  • 原文地址:https://www.cnblogs.com/AS30/p/2248078.html
Copyright © 2011-2022 走看看