Requirements
 
Prerequisite knowledge
To fully benefit from this tutorial, you will need to have an understanding of ColdFusion components as well as how to use ColdFusion with a database. You will also need to have an intermediate understanding of ActionScript 3.0.
 
User level
Intermediate
 
 
Required products
Adobe ColdFusion Enterprise Edition (2016 release) 8 (Download trial)
 
 
Sample files
Now that you can develop professional full-scale applications using Adobe AIR, you will need a way to effectively manage updates to these applications. Through this tutorial you will develop a management system for your Adobe AIR application updates that will work in Flash, Flex, or HTML/JavaScript Adobe AIR applications. ColdFusion 8 will be used to store and serve the updates to the Adobe AIR applications.

 
Updating Adobe AIR applications

Many of the nation's top companies are using Adobe AIR to develop interactive and connected applications. These applications will fuel the next iteration of the Internet. If your plan is to develop the next great AIR application, what will you do after you release your creation to the general public? During the creation process you might not think a great deal about updates, but when a serious coding flaw is revealed, updates could become your primary concern.
 
Under the hood
The Adobe AIR framework has a built-in mechanism for handling updates. This mechanism is quite powerful because it does not force you, the developer, to handle updates in any certain way. Instead it enables you to integrate updates in whatever manner that would be best for your application.
 
This mechanism allows you to call a method that will shut down the current application and load the new version while still preserving the data in the local folders. To ensure security and consistency, there are a few important things to keep in mind when using this integrated method for updating an AIR application:
 
  • The update file must have the same Application ID as the original application.
  • You must know the version number of the new application. You have to pass this to the update function of the Updater class.
  • The application closes to perform the update. You can only control what happens up to the point where you call the update function. When the update is completed, the application will restart.
 
Performing an update
In ActionScript the updates are handled with the flash.desktop.Updater class, and in JavaScript updates are handled by the air.Updater class. (You must include the AIRAliases.js file in your JavaScript application to use this notation. If you do not, the Updater class can only be referenced by window.runtime.flash.desktop.Updater.) To perform an update in either ActionScript (for Flash or Flex) or JavaScript, you need to follow the same three steps:
 
  1. Create an instance of the Updater class.
  2. Create a File object with a reference to the new application on your computer.
  3. Call the update function of the Updater class and pass in the version number of the new application.
Here is an ActionScript example from Adobe Livedocs Flex 3 Language Reference:
 
var updater:Updater = new Updater(); var airFile:File = File.desktopDirectory.resolvePath("Updated_Application.air"); var version:String = "2.01"; updater.update(airFile, version);
 
Obstacles in the updating process
The Updater class inside of Adobe AIR empowers the developer, but because of the flexibility, the developer has to write the implementation. There is no built-in method that "goes and checks the same place for a new version." In all likelihood, you will implement updates in a similar method across all of your Adobe AIR applications. This makes the update process a prime candidate for a central ActionScript class that will manage the entire update process. However, for this to be effective, it will need to work for any Adobe AIR application irrespective of whether it was created with Flex, Flash, or HTML/JavaScript.
 
This ActionScript class only manages half of the update process; you'll also need a method for serving the application updates. If the application is put on a web server and made accessible, you have very little ability to control how it is delivered. If older versions are left accessible, there is a risk for some users downloading an outdated version. It would be ideal to store the applications outside of your web tree and simply serve them when they are requested. This also leaves the door open for extensibility, because if you ultimately control the content, you can control how and when it is delivered.
 
The plan
To bring these ideas to fruition, both a client-side implementation and a server-side implementation will be needed.
  • Server-side implementation: This implementation consists of a database that stores information about the application releases. It serves the application files and returns information about which AIR file is the most up-to-date version. It also needs a front-end where the developer can enter the new versions of the AIR application. ColdFusion 8 will be powering the server-side.
  • Client-side implementation: This implementation needs to be able to ask the server for information on the latest update. It also has to react differently to different types of updates (critical, major, minor). The client side can either be a Flash, Flex, or HTML/JavaScript application built on AIR.

 
Leveraging ColdFusion in the update process

By utilizing ColdFusion 8 and an Apache Derby–embedded database, you can minimize the size of each update check to a single HTTPRequest. This creates two big advantages. First, this method can be used with both Flex/ActionScript and HTML/JavaScript applications. Second, by using the Derby-embedded database you are not relying on any services outside of ColdFusion 8. This also makes the application extremely easy to package and move to any other ColdFusion 8 server. By following this method it will also leave a detailed record of the releases of your application.
 
The embedded database is not the only new ColdFusion 8 feature that you will use in serving the Adobe AIR application files. You also will be taking advantage of the new CFZIP tag. With this tag, ColdFusion can look into an Adobe AIR application file and extract any information contained within its application descriptor file. Also, to take advantage of a lightweight data transfer format, you will be using the new ability in ColdFusion 8 where a ColdFusion component can return JavaScript Object Notation (JSON).
 
For the ColdFusion side of this application you will be using four files:
  • Application.cfc: This file verifies that the database table is created. If it is not, it creates it. The file also sets a few application scope variables.
  • UpdateManager.cfc: This file serves as your web service. The Adobe AIR applications call this file to get all of the update information.
  • serve.cfm: This file sends out the Adobe AIR application downloads.
  • index.cfm: This file allows the developer to add applications to the database and add release notes.
 
Installing the sample files
The sample files for this project can be found in the ColdFusion folder of the exercise files. Simply place these files in a directory on a ColdFusion 8 server, create the datasource (as outlined below), and update the Application.cfc file with the right path information.
 
Creating a database to store application information
The Derby database that will be used in the application can be created inside of the Data Sources section of the ColdFusion Administrator. To create the database:
  1. Create a new datasource with Apache Derby Embedded as the driver type.
  2. Provide the pathname where the database will reside on the server. If the database doesn't exist, select the Create Database check box (see Figure 1).
Creating the Derby-embedded database

Figure 1. Creating the Derby-embedded database
 
It only takes a simple database to store all of the application information. Table 1 displays the columns that will be used in the single table of the database.
 
Table 1. Columns for applications table
 
Column Data Type Description
uuid VARCHAR(36) The primary key for the database
dateTimeAdded TIMESTAMP The Date and Time the application was added to the database
applicationID VARCHAR(255) The appID from the Application Descriptor file
applicationName VARCHAR(255) The application name from the Application Descriptor file
applicationVersion VARCHAR(50) The application version from the Application Descriptor file
updateType INT The type of update: Critical, Major, or Minor
updateFile VARCHAR(255) The filename of the AIR file
releaseNotes LONG VARCHAR The release notes for this version of the AIR Application
The database creation process is handled in the Application.cfc file. This happens behind the scenes the first time you launch the application. Several application variables are also defined in the Application.cfc file. You will need to change these values to match your server.
 
Adding applications to the database
You will need to develop a simple front-end interface where you can add new versions of your Adobe AIR applications. By using this code, you can develop a simple form that will allow you to upload an AIR file as well as enter the additional information on each application update (see Figure 2); here is the code:
 
<form method="post" name="uploadForm" enctype="multipart/form-data"> AIR File<br /> <input name="FileContents" type="file"> <br /><br /> Update Type:<br /> <select name="updateType"> <option value="0">Critical</option> <option value="1">Major</option> <option value="2">Minor</option> </select> <br /> <br /> Release Notes:<br /> <textarea name="releaseNotes"></textarea> <br /> <br /> <input name="submit" type="submit" value="Upload File"><br /> </form>
Form for adding applications to the database
 
Figure 2. Form for adding applications to the database
 
You might notice that there are a few pieces of information missing from this form. It would be easy to create a form that would allow a developer to enter all of the information about an AIR application and upload the application file. However, the appID, version information, and name of the application are all contained within the Adobe AIR application's application descriptor file. Because an AIR application file is essentially a ZIP file, the CFZIP tag in ColdFusion 8 can be used to extract the application's information. The application descriptor file is always in the same place in the Adobe AIR package: META-INF/AIR/application.xml.
 
When the form is submitted, ColdFusion will perform the following actions:
 
  1. Move the uploaded Adobe AIR file to the directory that is defined in Application.cfc:
<cffile action = "upload" fileField = "FileContents" destination = "#APPLICATION.airApplicationDirectory#" nameConflict = "MakeUnique"> <cfset airFile= APPLICATION.airApplicationDirectory & APPLICATION.fileSeparator & cffile.serverFile />
  1. Read the Adobe AIR file with CFZIP to get the application information:
<cfzip action="read" file="#airFile#" entrypath="META-INF#fileSeparator#AIR#fileSeparator#application.xml" variable="applicationDescriptor" /> <cfset appDescriptor = XmlParse(applicationDescriptor,true) /> <cfset appID = appDescriptor['application']['id'].XMLText /> <cfset appVersion = appDescriptor['application']['version'].XMLText /> <cfset appName = appDescriptor['application']['name'].XMLText />
  1. Verify whether the same version of the application is already in the database; if so, display an error:
<cfquery name="ifDuplicate" datasource="#APPLICATION.dsn#"> SELECT * FROM versions WHERE applicationID = <cfqueryparam cfsqltype="cf_sql_varchar" value="#VARIABLES.appID#"> AND version = <cfqueryparam cfsqltype="cf_sql_varchar" value="#VARIABLES.appVersion#"> </cfquery> <cfif ifDuplicate.RecordCount NEQ 0> <cfset variables.message="Application Version Already in Database" />
  1. Add the application to the database with the information entered from the form:
<cfquery name="addApplicationUpdate" datasource="#APPLICATION.dsn#"> INSERT INTO versions uuid,dateTimeCreated,applicationID,version,name,updateType,updateFile,releaseNotes) VALUES ( '#CreateUUID()#', <cfqueryparam cfsqltype="cf_sql_timestamp" value="#DateFormat(now())# #TimeFormat(now())#">, <cfqueryparam cfsqltype="cf_sql_varchar" value="#VARIABLES.appID#">, <cfqueryparam cfsqltype="cf_sql_varchar" value="#VARIABLES.appVersion#">, <cfqueryparam cfsqltype="cf_sql_varchar" value="#VARIABLES.appName#">, <cfqueryparam cfsqltype="cf_sql_integer" value="#FORM.updateType#">, <cfqueryparam cfsqltype="cf_sql_varchar" value="#cffile.serverFile#">, <cfqueryparam cfsqltype="cf_sql_longvarchar" value="#FORM.releaseNotes#"> ) </cfquery> <cfset variables.message="Application Added" />
 
Communication between ColdFusion and Adobe AIR
Developers have already been hard at work creating a solution for completely encapsulating the update process inside of your AIR application. This causes a problem: part or all of the updated AIR application must be downloaded every time that you want to check for updates. ColdFusion becomes the perfect choice for handling this interaction, because you can shrink this process to a simple HTTPRequest.
 
There are many different methods for transmitting data between ColdFusion and an AIR application. For the purposes of this application, however, there is an additional requirement. To ensure that the update manager will work for all applications, the ColdFusion application must be accessible from Flash, Flex, and HTML/JavaScript applications built on AIR. To be sure that this works, you need to avoid classes that are only included in the Flex libraries (classes that begin with mx.). Fortunately, with ColdFusion you can expose your CFCs as soap web services and have them return JSON. Because JSON is extremely lightweight, it minimizes the amount of data that flows between the client and server.
 
Creating the ColdFusion Component
In this example's CFC, UpdateManager.cfc, there will be two methods. The method that the AIR applications will call is getUpdateJSON. This function serves as a wrapper for the main function, getLatestUpdate. By separating these methods, you could eventually write other public methods that would expose the data in a different format such as WDDX or XML.
 
<cffunction name="getUpdateJSON" access="remote" returntype="struct" returnformat="json"> <cfargument name="applicationID" type="String" required="true" /> <cfargument name="currentVersion" type="String" default="" /> <cfreturn getLatestVersion( ARGUMENTS.applicationID, ARGUMENTS.currentVersion ) /> </cffunction>
The main function, getLatestVersion, returns a ColdFusion structure. One of the "keys" of this structure will be updateCode. This will be the code that the ActionScript class will use to determine if an update is available. There are only three possibilities for this value: there is an update available, the application is not found in the database, and the application is already up-to-date. In the constructor of our CFC, you will need to define three values to serve as constants for these items.
 
<cfset THIS.UPDATE_AVAILABLE = 1 /> <cfset THIS.APPLICATION_NOT_FOUND = 2 /> <cfset THIS.APPLICATION_CURRENT = 3 />
The second key of the structure that will be returned is updateInfo. This will only be populated if there is an update available. If there is not an update available, it will be null.
 
The method getLatestVersion is what actually searches the database for the latest version. It takes two arguments, the applicationID and the currentVersion the application is running. The method assumes that the updates were added to the database chronologically. The latest version of the application is the newest version. It determines this by following these steps:
 
  1. Checks to see whether the current application version is in the database; if not, returns an updateCode indicating the following:
<cfif Len(trim(ARGUMENTS.currentVersion))> <cfquery name="applicationVersionQuery" datasource="#APPLICATION.dsn#"> SELECT * FROM versions WHERE applicationID = <cfqueryparam cfsqltype="cf_sql_varchar" value="#ARGUMENTS.applicationID#" /> AND version = <cfqueryparam cfsqltype="cf_sql_varchar" value="#ARGUMENTS.currentVersion#" /> </cfquery> <cfif applicationVersionQuery.RecordCount NEQ 1> <cfset returnStruct.updateCode=THIS.APPLICATION_NOT_FOUND /> <cfreturn returnStruct /> </cfif> </cfif>
  1. Query the database for the most recent version of the application where the version is newer than the current version:
<cfquery name="applicationQuery" datasource="#APPLICATION.dsn#"> SELECT * FROM versions WHERE dateTimeCreated = ( SELECT MAX(dateTimeCreated) FROM versions WHERE applicationID = <cfqueryparam cfsqltype="cf_sql_varchar" value="#ARGUMENTS.applicationID#" /> <cfif Len(trim(ARGUMENTS.currentVersion))> AND dateTimeCreated > <cfqueryparam cfsqltype="cf_sql_timestamp" value="#applicationVersionQuery.dateTimeCreated#" /> </cfif> ) AND applicationID = <cfqueryparam cfsqltype="cf_sql_varchar" value="#ARGUMENTS.applicationID#" /> </cfquery>
  1. Builds the structure to return with the information from the database; if no result, returns an updateCode stating that the application is up-to-date:
<cfif applicationQuery.RecordCount EQ 1> <cfset returnStruct.updateInfo.updateVersion=applicationQuery.version /> <cfset returnStruct.updateInfo.updateURL=APPLICATION.fileDownloadURL & "?id=" & applicationQuery.uuid /> <cfset returnStruct.updateInfo.updateType=applicationQuery.updateType /> <cfset returnStruct.updateInfo.releaseNotes=applicationQuery.releaseNotes /> <cfset returnStruct.updateCode=THIS.UPDATE_AVAILABLE /> <cfelse> <cfset returnStruct.updateCode=THIS.APPLICATION_CURRENT /> </cfif> <cfreturn returnStruct />
 
Serving the application file
From the information received in one of these web service calls, the AIR application will receive a URL whereby it can download the most recent version of the application. The URL points to the serve.cfm file, and the application-specific variables are passed in via GET. Outside of the code to parse the URL data, it only takes two ColdFusion tags to serve the AIR application, CFHEADER and CFCONTENT.
 
<cfquery name="getFileByID" datasource="#APPLICATION.dsn#"> SELECT updateFile FROM versions WHERE uuid = <cfqueryparam cfsqltype="cf_sql_varchar" value="#URL.id#"> </cfquery> <cfheader name="Content-disposition" value="attachment;filename=""Update.air"""> <cfcontent type="application/unknown" file="#APPLICATION.airApplicationDirectory##APPLICATION.fileSeparator##getFileByID.updateFile#" deletefile="No">
 
Managing updates in ActionScript
In any of the Adobe AIR development platforms (Flex, Flash, JavaScript) the update process will follow the same steps. The goal will be to encapsulate this process into an UpdateManager class that can be placed inside of your AIR application. This class will need to execute the steps in the following order:
 
  1. Retrieve information about the application from the application descriptor file.
  2. Query ColdFusion to determine if there is a newer version of the application available for download.
  3. If there is a new version of the application, dispatch an event detailing the specifics of the new version.
  4. Upon receiving a call to update, download the AIR application from the server through ColdFusion.
  5. Perform the AIR update.
One of the most unique features of the AIR runtime is the ability to use ActionScript classes inside of JavaScript-based Adobe AIR applications. With this feature, you will be able to develop a single UpdateManager class that accomplishes the steps above and include it in any AIR application.
 
Creating the UpdateManager class
To build the UpdateManager class inside of Flex, you will first need to create a new ActionScript class. In keeping with proper package management inside of a Flex application, I created folders in "reverse-dns" style. My blog domain is davidtucker.net, so my package path will be net.davidtucker. I will also create a folder called air which will also contain a folder named update (see Figure 3).
 
Creating the folders for the UpdateManager class
 
Figure 3. Creating the folders for the UpdateManager class
 
ActionScript is an event-driven language. The UpdateManager class will be able to communicate with the application by passing events to it. There is an easy way to give a class the ability to dispatch events, subclass the flash.events.EventDispatcher class. To accomplish this you need to first create the UpdateManager class, and then you need to enter flash.events.EventDispatcher in the superclass field of the New ActionScript Class window (see Figure 4).
 
Creating the UpdateManager class
 
Figure 4. Creating the UpdateManager class
 
Creating the needed properties and variables
The update class will need to have several properties and variables to function properly. First, you will need to create properties that reflect information on the current application.
 
private var _applicationID:String; private var _applicationName:String; private var _applicationVersion:String;
Next, you will need to define two properties that relate to the update process. The first property will give the URL to the ColdFusion CFC that you created in the previous step. You will also need a property that stores all of the information about an available update. This property will be of type AIRUpdate which you will create shortly.
 
private var _updateServer:String; private var _update:AIRUpdate;
After those properties you will need to create several variables that will make up the core functionality of this class. In the process of querying the server, downloading the updated application file, and installing the update you will need the following variables:
 
private var loader:URLLoader; private var urlStream:URLStream; private var updateFileData:ByteArray; private var updateFile:File;
 
Finally, you will need three constants that coincide with the constants in your ColdFusion component:
public static const UPDATE_AVAILABLE:uint = 1; public static const APPLICATION_NOT_FOUND:uint = 2; public static const APPLICATION_CURRENT:uint = 3;
 
Initializing the class
The constructor of the UpdateManager class will take only one argument, the URL of the CFC. Also, in the constructor you will need to set the application id, version, and name. Luckily, since Adobe AIR Beta 2 this information is contained within Shell.shell.applicationDesciptor. This variable stores your entire Adobe AIR application descriptor file. With a little XML parsing, you will have the needed values.
 
public function UpdateManager(server:String):void { _updateServer = server; var appXML:XML = NativeApplication.nativeApplication.applicationDescriptor; var air:Namespace = appXML.namespaceDeclarations()[0]; this.airApplicationID = appXML.air::id; this.airApplicationVersion = appXML.air::version; this.airApplicationName = appXML.air::name super(); }
 
Communicating with ColdFusion
The first method, check(), does the majority of the work in communicating with the ColdFusion server. It utilizes the flash.net.URLLoader class to talk to ColdFusion. Within Flex, it would make sense to use the Webservice class, which can easily talk with SOAP web services, but to ensure that this class will also work in Flash and JavaScript you will need to use the more generic URLLoader.
 
public function check():void { loader = new URLLoader(); loader.addEventListener(Event.COMPLETE,onResult); loader.addEventListener(IOErrorEvent.IO_ERROR,onFault); var params:URLVariables = new URLVariables(); params.method = "getUpdateJSON"; params.applicationID = _applicationID; params.currentVersion = _applicationVersion; var request:URLRequest = new URLRequest(_updateServer); request.data = params; request.method = "GET"; loader.load(request); }
 
Creating the AIRUpdate class
By creating a class that holds all of the information about an Adobe AIR update, you can greatly ease the transmission of information within your application. The purpose of this class will be to simply hold data, but not to perform any actions. This class is named AIRUpdate, and it contains the information from ColdFusion regarding the update. This class will need the following properties: release notes, update status, update file URL, and update version. It will also need constants to map the updateStatus type to its actual value. Each of the properties will be private, and each will have a "getter" to return the value. The constructor will take only one argument, an object that will contain the updateInfo structure passed from the server. This function will then populate the properties based on this object. By not allowing the properties to be set after instantiation you minimize the risk of potential coding errors.
 
public class AIRUpdate { public static const CRITICAL_UPDATE:uint = 0; public static const MAJOR_UPDATE:uint = 1; public static const MINOR_UPDATE:uint = 2; private var _releaseNotes:String; public function get releaseNotes():String { return _releaseNotes; } private var _updateStatus:int; public function get updateStatus():int { return _updateStatus; } private var _updateURL:String; public function get updateURL():String { return _updateURL; } private var _updateVersion:String; public function get updateVersion():String { return _updateVersion; } public function AIRUpdate(obj:Object) { this._releaseNotes = obj.RELEASENOTES; this._updateStatus = obj.UPDATETYPE; this._updateVersion = obj.UPDATEVERSION; this._updateURL = obj.UPDATEURL; } }
 
Reacting to events in ActionScript
Since ActionScript is an event-driven language, reacting to events will be central to your UpdateManager class.

 
Reacting to the CFC call

In the previous section you created references to two functions, onResult and onFault, that could be dispatched from the CFC call within the UpdateManager class. onResult is called when everything went according to plan, and onFault is called in the event of an IO error. The onFault method is relatively simple:
 
private function onFault(e:IOErrorEvent):void { this.dispatchEvent( new UpdateManagerFaultEvent( UpdateManagerFaultEvent.UPDATE_FAULT,'IOError: ' + e.errorID) ); }
This function has one purpose: to dispatch an event. It dispatches the UpdateManagerFaultEvent which you will create shortly. It also passes the errorID for the IO error to this new event.
 
The next function, onResult, handles many aspects of the UpdateManager class. First, it parses the result of the CFC call. Since ActionScript doesn't have a native WDDX parser, you will need to use the JSONDecoder that is included with the AS3CoreLib. Second, it populates the _update property if an update is available. Finally, it dispatches one of three events depending on what updateCode is returned by the ColdFusion server.
 
private function onResult(e:Event):void { if(e.target.data) { var result:Object = new JSONDecoder(e.target.data).getValue(); switch(result.UPDATECODE) { case UpdateManager.UPDATE_AVAILABLE: update = new AIRUpdate(result.UPDATEINFO); dispatchEvent( new UpdateManagerResultEvent(UpdateManagerResultEvent.UPDATE_AVAILABLE,_update) ); break; case UpdateManager.APPLICATION_NOT_FOUND: dispatchEvent( new UpdateManagerFaultEvent(UpdateManagerFaultEvent.APPLICATION_NOT_FOUND,"Application Not in Database") ); break; case UpdateManager.APPLICATION_CURRENT: dispatchEvent( new UpdateManagerResultEvent(UpdateManagerResultEvent.APPLICATION_CURRENT) ); break; } } }
 
Creating custom events
Essentially, one of two things will happen with the CFC call. It will either successfully communicate with your ColdFusion component, or it won't. Your UpdateManager class will need to pass an event for each of these occurrences. Ideally, the application will successfully communicate with ColdFusion and dispatch an event indicating that everything worked properly. This event will be named UpdateManagerResultEvent. However, in some situations the ColdFusion component may be unavailable or it may not have any record of your application; in that case the UpdateManager would dispatch an event indicating this failure. This event will be named UpdateManagerFaultEvent.
 
To create a custom event there are a few essentials. First, subclass the flash.events.Event class. Next, you will need to create at least one constant indicating the type of the event (such as UPDATE_ERROR). In creating the constructor, you will pass this value to the superclass (the instance of flash.events.Event). Finally, you will need to override the function clone. This method just creates a copy of the current event, and it is essential in the event flow.
 
You can also pass data in an event. In the first example you will need to pass a message with the UpdateManagerFaultEvent class. This will be a message describing the nature of the error. The class will also have two constants defined which correlate to the two situations where this class will be called: when the application is not found in the database and when there is an unspecified fault in reaching the CFC.
 
package net.davidtucker.air.update.events { import flash.events.Event; public class UpdateManagerFaultEvent extends Event { public static const UPDATE_FAULT:String = "updateFault"; public static const APPLICATION_NOT_FOUND:String = "updateNotFound"; public var message:String; public function UpdateManagerFaultEvent(type:String,message:String) { super(type); this.message = message; } override public function clone():Event { return new UpdateManagerFaultEvent(type, message); } } }
The next event is UpdateManagerResultEvent. This event has two custom properties as well as two constants. The first states that the application is current, and the second states that an update is available. The only property for this event is called data, and it will contain basic information about the update (if one is available).
 
Scripting the actual update process
The UpdateManager class can actually communicate with the ColdFusion server, but it cannot yet actually update your application. You will need to add a method to the class named update. This function will set the update process into motion by creating a URLStream object to download the actual update file. Before this process begins, the function will also ensure that an updateURL has actually been set. If not, it will pass a string to the console indicating that it doesn't have a valid update available.
 
public function update():void { if(this._update.updateURL != null) { var request:URLRequest = new URLRequest(_update.updateURL); urlStream = new URLStream(); updateFileData = new ByteArray(); urlStream.addEventListener(Event.COMPLETE, onStreamComplete); urlStream.load(request); } else { trace("No Update Available"); } }
After downloading, the actual AIR file will be wrapped in a ByteArray object. This object will then be written to the local file system. This entire interaction takes place over two methods:
 
private function onStreamComplete(event:Event):void { urlStream.readBytes(updateFileData, 0, urlStream.bytesAvailable); writeUpdateFile(); } private function writeUpdateFile():void { updateFile = File.applicationStorageDirectory.resolvePath("Update.air"); var fileStream:FileStream = new FileStream(); fileStream.addEventListener(Event.CLOSE, performUpdate); fileStream.openAsync(updateFile, FileMode.WRITE); fileStream.writeBytes(updateFileData, 0, updateFileData.length); fileStream.close(); }
Finally, if the file has been written to the local file system, the performUpdate function is called. This is where the actual update occurs.
 
private function performUpdate(event:Event):void { var updater:Updater = new Updater(); updater.update(updateFile,_update.updateVersion); }
 
Integrating the update manager
The hard work is done. Because of the work that was done in the previous steps, the integration of the update manager is the easy part.
 
Integrating the UpdateManager class with Flex and Flash
To use the UpdateManager class with your Flex or Flash Adobe AIR application, you simply need to add the code that you created to the source folder. If you are using Flex with the version that is compiled with this tutorial, you can also add the SWC file to your Flex build path. If you are using Flash, you simply need to add the source folder to your classpath.
 
Once this is complete, you can define the UpdateManager in Actionscript:
 
import net.davidtucker.air.update.AIRUpdate; import net.davidtucker.air.update.events.*; import net.davidtucker.air.update.UpdateManager; private var um:UpdateManager; private function init():void { um = new UpdateManager('http://localhost:8500/UpdateManager/UpdateManager.cfc'); um.addEventListener(UpdateManagerResultEvent.UPDATE_AVAILABLE,onResult); um.addEventListener(UpdateManagerFaultEvent.UPDATE_FAULT,onFault); um.addEventListener(UpdateManagerResultEvent.APPLICATION_CURRENT,onResult); um.addEventListener(UpdateManagerFaultEvent.APPLICATION_NOT_FOUND,onFault); }
For this point, you just need to write your functions to handle the events. When the class is instantiated, you can call the um.check() function to see if there is an update available. If there is an update available, you just need to call the um.update() function, and your application will update itself.
 
Integrating the UpdateManager with HTML/JavaScript
A JavaScript-based Adobe AIR application can import SWF files with ActionScript 3.0 classes compiled into them. A SWF file of the source code is included with the files for this tutorial. Also included is an aliases file for the class names. First, you will need to import the SWF file and the aliases file in the correct order in the HEAD section of your HTML document:
 
<script type="application/x-shockwave-flash" src="UpdateManager.swf" ></script> <script type="text/javascript" src="UpdateManagerAliases.js"></script>
 
Next, you need to instantiate the class and add the event listeners:
 
var um = {}; function doLoad() { // Variable To Ensure that AIRUpdate Gets Compiled In var au = new air.um.AIRUpdate(); um = new air.um.UpdateManager('http://localhost:8500/UpdateManager/UpdateManager.cfc'); um.addEventListener(air.um.UpdateManagerFaultEvent.APPLICATION_NOT_FOUND, onFaultEvent); um.addEventListener(air.um.UpdateManagerFaultEvent.UPDATE_FAULT, onFaultEvent); um.addEventListener(air.um.UpdateManagerResultEvent.APPLICATION_CURRENT, onApplicationCurrent); um.addEventListener(air.um.UpdateManagerResultEvent.UPDATE_AVAILABLE, onUpdateAvailable); }
Just as with the Flash/Flex sample, you can call the um.check() function to check whether there are any updates available. If there is an update available, call um.update() to perform the update.
 
Viewing the sample applications
The source code for three sample AIR applications is included with this tutorial: one for Flex, Flash, and JavaScript. These applications, as illustrated in Figure 5, enable you to test the updating process.
 
The Update Inspector sample application
 
Figure 5. The Update Inspector sample application

 
Where to go from here

This application was written with extensibility in mind. Because the application serves all of the AIR files, you have total control over how your AIR application is distributed. This opens new doors of possibility. You could expand the current code to:
 
  • Require a user name and password to download the AIR application.
  • Implement a licensing method for your AIR application by requiring a serial number to retrieve the AIR application.
  • Collect a record of every download as well as the version number which would provide accurate metrics of what percentage of users are using what version of the application.
  • Intelligently detect the AIR application's connection status and only check for updates if the user has a network connection.
Feel free to take the code from this article and adapt it to your situation. I will look forward to seeing all of the variations that are created. In your development, be sure to check out other articles and getting-started tutorials in the Adobe AIR Developer Center for Flex, or HTML/Ajax, or the ColdFusion Developer Center, and the Flex Developer Center.