Swiz Desktop for AIR support

When you develop AIR applications you see repeating tasks which you have in all projects. You need to take care about the update process and online status. I am developing all my applications with the Swiz framework so I tried to come up with some re-usable code which fits nicely into Swiz.

Source and Download

Define the SwizUpdateBean in your Swiz BeanLoader:

<desktop:SwizUpdateBean xmlns:desktop="com.soenkerohde.desktop.*"
	id="swizUpdateBean"
	updateUrl="http://yourdomain.com/YourApp.air"
	autoCheckUpdate="true" autoStartUpdate="true" />

We have set the update URL and the flag to automatically check for an update and automatically download and invoke the update when a newer version is online.
However you may only want to use this in a very early stage of your development to simply ensure that the user always get’s the latest version. The user experience is a bit odd though since the user get’s no visual feedback at all and might be upset when the app closes, updates and restarts itself.

Control Update
A controller can add event listeners to the SwizUpdateBean to get notified when the update phase change so you get a point to interact. You can autowire the bean also against a setter which gives you the possibility to add event listeners:

package com.soenkerohde.example {
 
	import com.soenkerohde.example.UpdateWindow;
	import com.soenkerohde.desktop.ISwizUpdateBean;
	import com.soenkerohde.desktop.event.OnlineEvent;
	import com.soenkerohde.desktop.event.UpdateEvent;
 
	import org.swizframework.Swiz;
 
	import spark.components.Window;
 
	public class UpdateController {
 
		[Autowire]
		public function set updateBean( bean : ISwizUpdateBean ) : void {
			bean.addEventListener( UpdateEvent.VERSION_INFO, versionInfoHandler, false, 0, true );
			bean.addEventListener( UpdateEvent.UPDATE, updateHandler, false, 0, true );
			bean.addEventListener( OnlineEvent.CHANGE, onlineHandler, false, 0, true );
		}
 
		protected function versionInfoHandler( event : UpdateEvent ) : void {
			// when locale and remote version are different show update window
			if ( event.updateInfo.localVersion != event.updateInfo.remoteVersion ) {
				var updateWindow:Window = new UpdateWindow();
				Swiz.registerWindow( updateWindow );
				updateWindow.open();
				updateWindow.move( 50, 50 );
			}
		}
 
		protected function updateHandler( event : UpdateEvent ) : void {
			// prevent automatic update and wait for user to invoke
			event.preventDefault();
		}
 
		protected function onlineHandler( event : OnlineEvent ) : void {
			var online:Boolean = event.online;
			// TODO handle online status
		}
 
	}
}

Visual Feedback
Since the SwizUpdateBean is loaded in the BeanLoader we can autowire it into any view. The SwizUpdateBean implements the ISwizUpdateBean so we can autowire the interface by type without caring about the id. The ISwizUpdateBean has a getter for updateInfo which is a bindable getter for detailed update status information. In the example below we autowire it by property. We could also access it from the swizUpdateBean.updateInfo but I like it more as an extra member variable.

UpdateInfo gives you access to:

  • localVersion
  • remoteVersion
  • percent
  • bytesLoaded
  • bytesTotal
  • kiloBytePerSecond (we calculate the connection speed of the user)
  • timeRemaing (the time in seconds we have calculated remains to download the update)
  • updateFilePath (the path to the downloaded update file)
<s:Window width="240" height="210"
		  xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark"
		  xmlns:mx="library://ns.adobe.com/flex/halo" title="Update" alwaysInFront="true" resizable="false" showStatusBar="false">
 
	<s:layout>
		<s:BasicLayout />
	</s:layout>
 
	<fx:Script>
		<![CDATA[
			import flash.events.MouseEvent;
			import com.soenkerohde.desktop.ISwizUpdateBean;
			import com.soenkerohde.desktop.info.IUpdateInfo;
 
			[Bindable]
			[Autowire(bean="swizUpdateBean", property="updateInfo")]
			public var updateInfo:IUpdateInfo;
 
			[Bindable]
			[Autowire]
			public var swizUpdateBean:ISwizUpdateBean;
 
			protected function clickHandler( event : MouseEvent ) : void {
				swizUpdateBean.executeUpdate( false )
			}
		]]>
	</fx:Script>
 
	<s:VGroup horizontalCenter="0">
		<mx:Form verticalGap="0">
			<mx:FormItem label="Your Version:">
				<s:Label text="{updateInfo.localVersion}" />
			</mx:FormItem>
			<mx:FormItem label="New Version:">
				<s:Label text="{updateInfo.remoteVersion}" />
			</mx:FormItem>
		</mx:Form>
 
		<s:Label text="Progress: {updateInfo.bytesLoaded}/{updateInfo.bytesTotal} Bytes" />
		<mx:ProgressBar indeterminate="false" label="Remaining: {updateInfo.timeRemaining} sec with {updateInfo.kiloBytePerSecond} KB/s" mode="polled"
						source="{updateInfo}" />
 
	</s:VGroup>
 
	<s:Button bottom="10"
			  horizontalCenter="0" label="Update and Restart" enabled="{updateInfo.complete}" click="clickHandler(event)" />
 
</s:Window>

You see how easy it is to implement the ProgressBar. Because the updateInfo object has a getter for bytesLoaded and bytesTotal we only have to set the mode to “polled” and can set the object itself as the source of the ProgressBar.

Feedback appreciated or just fork the project on GitHub if you want to extend it.

Comments are closed.