Часто встречаю вопрос типа "Как сделать обновление приложения AIR". Не проверял, есть ли в сети что-то подобное (наверняка есть), а просто решил выложить свой класс для этой процедуры. Он далеко не отшлифован и функционал предполагалось значительно расширить. Но сразу не сделал, а времени на это уже нет. Поэтому, кому понравится, может расширять и модернизировать этот класс без всяческих оговорок.
Итак, при запуске (не обязательно) AIR-приложения определяем версию приложения следующим кодом:
var descriptor:XML = nativeApplication.applicationDescriptor; var air:Namespace = descriptor.namespaceDeclarations()[0]; var version:String = String(descriptor.air::version);
Версия же приложения устанавливается в файле application.xml до сборки приложения. Например.
<version>1.0</version>
Затем подключаете мой класс для обновления приложения, который сделает всю работу.
WebUpdate.instance.start(version);
Для функционирования обновления необходимо выложить в сеть для доступа само приложение (файл формата AIR) и текстовый файл с единственной записью, например:
1.0.1
Класс распарсит строку и сделает всё необходимое.
Вот пример кода корневого компонента для тестов:
<?xml version="1.0" encoding="utf-8"?>
<mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml"
width="320"
height="240"
windowComplete="onWindowsComplete(event)"
title="AIR Web Update Tutorial"
status="AIR Web Update Tutorial"
showStatusBar="true">
<mx:Script>
<![CDATA[
import flash.events.Event;
import ru.pixeltyumen.air.utils.WebUpdate;
private function onWindowsComplete (e:Event):void {
var descriptor:XML = nativeApplication.applicationDescriptor;
var air:Namespace = descriptor.namespaceDeclarations()[0];
var version:String = String(descriptor.air::version);
WebUpdate.instance.start(version);
}
]]>
</mx:Script>
<mx:TextArea width="100%" height="100%" editable="false" selectable="false"
text="This application is demonstrating the process of WebUpdate class job." />
</mx:WindowedApplication>
А это код самого класса:
package ru.pixeltyumen.air.utils
{
import air.net.URLMonitor;
import flash.desktop.Updater;
import flash.events.StatusEvent;
import flash.filesystem.File;
import flash.filesystem.FileStream;
import flash.filesystem.FileMode;
import flash.events.Event;
import flash.events.IOErrorEvent;
import flash.events.ProgressEvent;
import flash.events.EventDispatcher;
import flash.utils.ByteArray;
import mx.events.CloseEvent;
import flash.net.URLLoader;
import flash.net.URLRequest;
import flash.net.URLStream;
import mx.controls.Alert;
/**
* ...
* @author .p.i.x.e.l.
*/
public class WebUpdate extends EventDispatcher
{
public static const ONLY_UPDATE_ALERT:String = "ONLY_UPDATE_ALERT";
public static const UPDATE_AND_EQUAL_ALERT:String = "UPDATE_AND_EQUAL_ALERT";
public static const DETAILED_ALERT:String = "DETAILED_ALERT";
private static const NEED_UPDATE:String = "NEED_UPDATE";
private static const EQUAL_VERSIONS:String = "EQUAL_VERSIONS";
private static const NEWEST_VERSION:String = "NEWEST_VERSION";
private static var _instance:WebUpdate;
private var _netStatus:URLMonitor;
private var _currentVersion:String;
private var _updateVersion:String;
private var _state:String = EQUAL_VERSIONS;
private var _mode:String = NEED_UPDATE;
private var _versionTextUrl:String =
"http://url_for_text_file_with_version_number";
private var _updateAppUrl:String =
"http://url_for_last_version_of_application";
// Message strings
private var _equalTitleString:String = "Внимание!";
private var _equalTextString:String = "У вас последняя версия приложения, не требующая обновления.";
private var _newestTitleString:String = "Внимание!";
private var _newestTextString:String = "Странно, но ваша версия новее!";
private var _olderTitleString:String = "Внимание!";
private var _olderTextString:String = "Ваша версия более старая и требует обновления. Приступить к обновлению?";
private var _errorTitleString:String = "Ошибка!";
private var _errorTextString:String = "Сервер обновлений не доступен! Проверте настройки сети или повторите операцию позже.";
/**
* Constructor
*/
public function WebUpdate () {
if (_instance != null) {
throw new Error("This class ru.pixeltyumen.air.utils.WebUpdate is singleton!");
}
_netStatus = new URLMonitor(new URLRequest(_updateAppUrl));
_netStatus.start();
}
/**
* Instance of class
*/
static public function get instance ():WebUpdate {
if (_instance == null) {
_instance = new WebUpdate();
}
return _instance;
}
/**
* Setter for URL of application file
*/
public function set updateAppUrl (s:String):void {
_updateAppUrl = s;
}
/**
* Setter for URL of version text-file
*/
public function set updateVersionUrl (s:String):void {
_versionTextUrl = s;
}
/**
*
* @param currentVersion
* @param mode
*/
public function start (currentVersion:String, mode:Boolean = false):void {
_mode = mode ? UPDATE_AND_EQUAL_ALERT : NEED_UPDATE;
_currentVersion = currentVersion;
if (!_netStatus.available && mode) {
Alert.show(_errorTextString, _errorTitleString);
return;
}
var loader:URLLoader = new URLLoader();
loader.addEventListener(Event.COMPLETE, versionSignComplete);
// add another error handlers here...
loader.load(new URLRequest(_versionTextUrl));
}
/**
* Complete handler of getting last version
* @param e
*/
private function versionSignComplete (e:Event):void {
_updateVersion = e.target.data as String;
compareVersions();
if (_state == EQUAL_VERSIONS && _mode == (UPDATE_AND_EQUAL_ALERT || DETAILED_ALERT)) {
Alert.show(_equalTextString, _equalTitleString);
}
if (_state == NEWEST_VERSION && _mode == DETAILED_ALERT) {
Alert.show(_newestTextString, _newestTitleString);
}
if (_state == NEED_UPDATE) {
Alert.show(
_olderTextString,
_olderTitleString,
Alert.YES | Alert.NO,
null,
confirmUpdate,
null
);
}
}
/**
* Compare versions
*/
private function compareVersions ():void {
_state = EQUAL_VERSIONS;
var curArray:Array = _currentVersion.split(".");
var updArray:Array = _updateVersion.split(".");
try {
for (var i:uint = 0; i < curArray.length; i++) {
if (curArray[i] && updArray[i] && uint(curArray[i]) < uint(updArray[i])) {
_state = NEED_UPDATE;
return;
}
}
} catch (e:Error) { errorHandler(null); }
}
/**
*
* @param e
*/
private function confirmUpdate (e:CloseEvent):void {
if (e.detail == Alert.YES) {
var stream:URLStream = new URLStream();
//stream.addEventListener(ProgressEvent.PROGRESS, progressHandler);
stream.addEventListener(Event.COMPLETE, completeHandler);
stream.addEventListener(IOErrorEvent.IO_ERROR, errorHandler);
// add other error handler
stream.load(new URLRequest(_updateAppUrl));
}
}
/**
*
* @param e
*/
private function progressHandler (e:ProgressEvent):void {
"Downloading update " + e.bytesLoaded + " of " + e.bytesTotal + " bytes";
}
/**
*
* @param e
*/
private function completeHandler (e:Event):void {
var urlStream:URLStream = e.target as URLStream;
var fileStream:FileStream = new FileStream();
var file:File = File.applicationStorageDirectory.resolvePath("newVersion.air");
fileStream.open(file, FileMode.WRITE);
var bytes:ByteArray = new ByteArray();
urlStream.readBytes(bytes);
fileStream.writeBytes(bytes);
fileStream.close();
var updater:Updater = new Updater();
updater.update(file, _updateVersion);
}
/**
*
* @param e
*/
private function errorHandler (e:Event):void {
Alert.show(_errorTextString, _errorTitleString);
}
}
}
Только не забудьте поставить нужные URL в переменные _versionTextUrl и _updateAppUrl.
Отправить комментарий