Adobe Air‎ > ‎

自動update

新しいバージョンをAIRアプリケーション側で自動的にチェックして、最新バージョンがあれば更新する機能...のやり方です。
2008/09/08追記 Adobe AIR Update Frameworkで行なう方法の記事を追加しました。こちらの方法の方がよいかも。

AIRには、flash.desktop.Updaterというクラスが提供されていて、これを使うとアプリのUpdateが行なう事ができます。
ただし!最新バージョンのチェックと、モジュールのダウンロードは自作する必要があります。
ダウンロードしたもの と 新しいバージョン をUpdaterに渡してあげることでUpdateが実行できます。

私がASlimTimerを作成したときに使った方法をご紹介。

最新バージョンがあるかどうかをチェック

バージョン番号と、ダウンロードURLを記述したXMLファイルをWEB上に配置します。
フォーマットは好きな形で大丈夫ですが、私は以下の形にしました。
<version>
        <version>1.0.0</version>
        <url>http://******.air</url>
</version>
ASlimTimerで使っているXMLは http://www.assembla.com/spaces/ASlimTimer/documents/bqUoAKBcOr3B8uab7jnrAJ/download/version.xml にしています。

このURLにアクセスして、versionの番号と、実行中アプリケーションのバージョンとをチェックして違っていたら、Updateするようにします。

/* VersionXMLにアクセスし、チェックをする。 引数は処理完了時にCallBackする関数。*/
public function checkUpdate(onCompleted:Function):void {
    completedFunction = onCompleted
    var versionLoader:URLLoader = new URLLoader();
    versionLoader.addEventListener(Event.COMPLETE, onVersionXmlLoaded);
    versionLoader.addEventListener(IOErrorEvent.IO_ERROR, onError);
    versionLoader.load(new URLRequest(VERSION_URL));   
}

/* エラー発生時 */
private function onError(event:IOErrorEvent):void {
    completedFunction();
}

/* VersionXMLをダウンロードしてVersionをチェック */
private var remoteVersion:String;
private function onVersionXmlLoaded(event:Event):void {
    var xml:XML = new XML(event.target.data);
    remoteVersion = xml.version;

    var appDescriptor:XML = NativeApplication.nativeApplication.applicationDescriptor;
    var ns:Namespace = appDescriptor.namespace();
    var appVersion:String = appDescriptor.ns::version;

    if (remoteVersion != appVersion) {
        Alert.show("It is possible to update it to a new version. \n" +
                    "Do you update it?\n\n" +
                    "Now version: " + appVersion + "\n" +
                    "New version: " + remoteVersion,
                    'Confirm',
                    Alert.YES | Alert.NO, null,
                function (event:CloseEvent):void {
                    if (event.detail == Alert.YES) {
                        downloadNewPackage(xml.url);
                    } else {
                        completedFunction();
                    }
                }
        );
    } else {
        completedFunction();
    }
}

実行中のアプリケーションのバージョンは以下で取得できます。

    var appDescriptor:XML = NativeApplication.nativeApplication.applicationDescriptor;
    var ns:Namespace = appDescriptor.namespace();
    var appVersion:String = appDescriptor.ns::version;

引数として受けているonCompletedのCallBack関数は無くてOKです。
私の場合はこの更新の処理が終わってから行いたい処理が別にあったので、渡しているだけでして。。

また、上記のコードではダイアログで確認メッセージも出しています。
勝手に始まるよりは、あった方が親切と思います。
(勝手に画面がいなくなって違う画面が出てきたらびっくりするし)

XMLで記述されたURL(xml.url)を使ってダウンロードを行なっていきます(downloadNewPackage)。それは次の章で。

新しいAirパッケージをダウンロード

private var popup:ProgressWindow;
/* Download NewPackage */
private function downloadNewPackage(urlString:String):void {
    popup = ProgressWindow(PopUpManager.createPopUp(DisplayObject(Application.application), ProgressWindow, true));
    PopUpManager.centerPopUp(popup);
    popup.title = "ASlimTimer Update";
    popup.progress.label = "download...";
   
    var urlReq:URLRequest = new URLRequest(urlString);
    urlStream = new URLStream();
    urlStream.addEventListener(Event.COMPLETE, loaded);
    urlStream.addEventListener(IOErrorEvent.IO_ERROR, onError);
    popup.progress.source = urlStream;
    urlStream.load(urlReq);
}

Airパッケージをダウンロードには、それなりの時間がかかるはずなので、プログレスダイアログを表示するようにしています。
ここで使っている、ProgressWindowのクラスは以下の内容になります。

ProgressWindow.mxml
<?xml version="1.0" encoding="UTF-8"?>
<mx:TitleWindow xmlns:mx="http://www.adobe.com/2006/mxml" width="200" layout="absolute" alpha="0.7">
    <mx:ProgressBar id="progress" labelPlacement="bottom" minimum="0" visible="true" width="100%"/>
</mx:TitleWindow>

ProgressBarを一つだけ配置した単純な画面です。
ProgressBarをダウンロード状況に合わせて進めるためには、
ProgressBarのsourceにURLStreamのオブジェクトを設定してあげればOK!簡単ですねー

次に、LOADが完了したときに実行する loaded のFunctionは以下になります。

private function loaded(event:Event):void {   
    var fileData:ByteArray = new ByteArray();
    urlStream.readBytes(fileData, 0, urlStream.bytesAvailable);
    writeAirFile(fileData);
}

private function writeAirFile(fileData:ByteArray):void {
    var file:File = File.applicationStorageDirectory.resolvePath("DownloadNewFile.air");
    var fileStream:FileStream = new FileStream();
    fileStream.open(file, FileMode.WRITE);
    fileStream.writeBytes(fileData, 0, fileData.length);
    fileStream.close();
    runUpdater(file);
}

ByteArrayに変換してから、File.applicationStorageDirectoryにファイルとして保存しています。
File.applicationStorageDirectoryというのは、AIRアプリケーション固有の保存ディレクトリです。
次に、保存したファイルをUpdaterのクラスを使ってUpdateを実行していきます。

Updateを行なう

private function runUpdater(airFile:File):void {
    var updater:Updater = new Updater();
    updater.update(airFile, remoteVersion);
    completedFunction();
    PopUpManager.removePopUp(popup);
}

Updaterのクラスをインスタンスして、作成したファイルと、新しいバージョン をupdateメソッドに指定してあげればOK!
そうすると、現在起動中のアプリケーションを終了し、AIRのUpdateダイアログが出てきて更新を始め、更新が完了した時点でアプリケーションを起動してくれます。

このAIRの機能である更新のワークフローは独自にくむ事ができるようです。
独自に組みたい場合には、ApplicationDescriptor(application.xml)の設定にて<customUpdateUI>をtrueに設定します。
そうすると、Updater#updateを実行しても、AIRのUpdateダイアログが出てきて....というワークフローが実行されなくなります。
多分、自分でプログラム書いてUpdate処理をするって形なんだろうと思います。
ASlimTimerでは面倒なので、AIRの機能を使ってやってますw

また、このUpdaterの処理はADTで実行している(開発中など)場合は、実行できないので注意が必要です。
これでコーディングは終了です♪

最後に

このコードの全体像は、ASlimTimerのコードを見てみてください。
http://trac.assembla.com/aslimtimer/browser/trunk/controller/ASlimTimerUpdater.as

実際動かしてみたい!という場合には、ASlimTimerの古いバージョンを実行してもらえれば、起動時にUpdateが実行される(はず)なので試してみてください。
ASlimTimer-1.0.0.air
↑AIRランタイムが入った状態で上記をダウンロードして実行!

Comments