21 March 2011
To benefit most from this article, you should be familiar with the AIR runtime; Flex Builder, Aptana Studio, or Flash CS4 Professional; and ActionScript 3.0 or JavaScript.
Update framework
Web server
Any web server will do. You need this for testing the update
Intermediate
Every time I create an AIR application that I know will be live someday, I always add support for updating it with the Adobe AIR update framework. Sooner rather than later, your application will need an update. Picture this: your application is a tremendous success and many people have installed it. A short time later you have a fix for a security issue, or you've just added the coolest feature ever. Suddenly you have a problem: how do you push this update to clients who already have installed your application?
If the application doesn't include support for the update process, then your problem is now a big one. The users will have to uninstall the current version, download the new one, and install it. This is hardly a friendly workflow.
The Adobe AIR update framework provides developers with APIs to create AIR applications that can be updated very easily. It comes in two flavors: one has a default user interface, and the other requires you to create your own UI and hook it up to the events that this framework provides.
The default user interface option uses Flex components; so if you are planning to create your AIR application using Flash, you can't use it. If you create the application with Flex or Ajax, you can use either one.
This article explains how to use the Adobe AIR update framework to easily and seamlessly push updates to AIR applications created using Flash, Flex, or Ajax.
In the first four sections I'm discussing the general workflow and how you can use it with AIR 1.5.x or 2. In the last two sections I talk about the changes in the update framework introduced by AIR 2.5.
Note: The update framework is not working for Extended Profile (Native installers) and for mobile applications.
Using the update framework is easy. The simplest approach has three main steps (for an application created in Flex using the update framework with the default UI):
Figure 1 shows a typical workflow for an application that uses the update framework.
If the version number from the updater descriptor file is higher than the version number of the currently installed application (as set by the version tag from the application descriptor file), the update framework determines that a new version is available.
Furthermore, the version written in the updater descriptor file must be identical to the version set in the new AIR file (the packaged AIR application). If they are not, an error will be raised and the update will not be performed. For a list of the error codes that the framework can throw, refer to the language reference for ActionScript or HTML/JavaScript developers.
For version formats, you can use any of several conventions:
To keep it simple and easy to follow, I use the first one.
One of the main benefits of the update framework is the ability to easily roll out updates to fix security issues. It would be a little ironic if the framework itself didn't provide security when it is used, and instead allowed an installed application to be downgraded, for example.
Fortunately, the update framework enhances the security of your application. For example, there is no way to "update" your application with an older version. This means that there is no way to accidentally roll out a version older than the ones that are installed by your clients. The same version number must be set in the AIR file (the AIR application packaged for release) and in the updater descriptor file. Furthermore, an AIR application can't be updated unless it was signed with the same certificate as the one that is being used to update it.
Keep in mind that the update framework needs a connection to the Internet or your local network. The new version and the updater descriptor files sit on a web server. Thus, when the application checks for updates it needs a connection to reach these files. If there is no connection, no update will be possible.
Because the Adobe AIR update framework is flexible, you decide how best to handle the update process. Your process can implement any of the following approaches:
Enough talk; time to look at some code. For the first example I will use Flex and the Adobe AIR update framework library with the user interface. To be honest I always use the version with the UI; I am too lazy to bother with creating my own UI.
Note: If you use CSS files to change the appearance of your AIR application and you use general styles (for example, for the Button or Scrollbar) that are not set as a class name but apply across your application, then these changes will also apply to the UI provided by the update framework. Keep this in mind, and always check the update framework UI when you use CSS.
If you don't want to create the project step by step, you can use the archive file provided with this article. To import the file, choose Import > Flex Builder > Flex Project and select the air_updater_flex.zip file.
Although you can create an AIR application using the command-line tools provided with the AIR SDK and your favorite text editor, I prefer to use Flex Builder:
With all the bits in place, it is time to add the ActionScript to implement the update feature:
checkUpdate for the event creationComplete of the WindowedApplication:<?xml version="1.0" encoding="utf-8"?>
<mx:WindowedApplication xmlns:mx="/2006/mxml" layout="absolute" creationComplete="checkUpdate()">
The function checkUpdate will be called every time the application is loaded.
<mx:Script>
<![CDATA[
import air.update.events.UpdateEvent;
import mx.controls.Alert;
import flash.events.ErrorEvent;
import air.update.ApplicationUpdaterUI;
/**
* @var the object that that handles the update related actions
*/
private var appUpdater:ApplicationUpdaterUI = new ApplicationUpdaterUI();
/**
* This function is triggered when the application finished to load;
* Here we initialize <code>appUpdater</code> and set some properties
*/
private function checkUpdate():void {
setApplicationVersion();
// we set the URL for the update.xml file
appUpdater.updateURL = "http://localhost/updater/update.xml";
//we set the event handlers for INITIALIZED nad ERROR
appUpdater.addEventListener(UpdateEvent.INITIALIZED, onUpdate);
appUpdater.addEventListener(ErrorEvent.ERROR, onError);
//we can hide the dialog asking for permission for checking for a new update;
//if you want to see it just leave the default value (or set true).
appUpdater.isCheckForUpdateVisible = false;
//if isFileUpdateVisible is set to true, File Update, File No Update,
//and File Error dialog boxes will be displayed
appUpdater.isFileUpdateVisible = false;
//if isInstallUpdateVisible is set to true, the dialog box for installing the update is visible
appUpdater.isInstallUpdateVisible = false;
//we initialize the updater
appUpdater.initialize();
}
/**
* Handler function triggered by the ApplicationUpdater.initialize;
* The updater was initialized and it is ready to take commands
* (such as <code>checkNow()</code>
* @param UpdateEvent
*/
private function onUpdate(event:UpdateEvent):void {
//start the process of checking for a new update and to install
appUpdater.checkNow();
}
/**
* Handler function for error events triggered by the ApplicationUpdater.initialize
* @param ErrorEvent
*/
private function onError(event:ErrorEvent):void {
Alert.show(event.toString());
}
/**
* A simple code just to read the current version of the application
* and display it in a label.
*/
private function setApplicationVersion():void {
var appXML:XML = NativeApplication.nativeApplication.applicationDescriptor;
var ns:Namespace = appXML.namespace();
lblAppVersion.text = "App version:" + appXML.ns::version;
}
]]>
</mx:Script>
In this code, you add an mx:script tag and create a variable appUpdater that will keep a reference to the updater object (this object will be your interface to the framework). Then create the function checkUpdate(), which will be in charge of initializing and setting some values needed by the updater object. The updateURL property tells the updater where to find the updater descriptor file (you will create this file later). If you don't set the updateURL property correctly, the update will not work.
Next, you'll need to register two functions for the error event and initialized event. If the isCheckForUpdateVisible property is true, then the user is given the option to check for a new version or not. In this case, set it to false, which will bypass this dialog box when checking for a new version. The last function call, appUpdater.initialize(), does exactly what the name implies. When the updater is initialized it calls the listener you have registered for the initialize event, and inside this listener you start the process of checking for a new version.
The next two functions are the implementations for the event listeners for the error and initialize events. Once the onUpdate() listener gets called, it means the updater was initialized and it is ready to take commands. The onUpdate() function calls the method checkNow() on the updater, starting the update process.
The last function, setApplicationVersion(), just reads the current version of the app and displays it using a label.
Finally, add a label component to display the current version of the application:
<mx:VBox>
<mx:Label id="lblAppVersion" width="300"/>
</mx:VBox>
You have all the code in the application in place; now it is time to put in place the bits you need on the server. First create the file update.xml inside the updater folder from the project:
<?xml version="1.0" encoding="utf-8"?>
<update xmlns="http://ns.adobe.com/air/framework/update/description/1.0">
<version>2.9</version>
<url>http://localhost/updater/air_updater_flex.air</url>
<description><![CDATA[
This version has fixes for the following known issues:
*First issue
*Second issue
]]></description>
</update>
This file lets you define the URL where the new version of the application can be downloaded, set the version number, and specify the description text you want to display to the user.
All the code is in place but you are not finished yet. It is very important not to forget this: in order for the update to work you need to carefully set the same version number in two files—the updater descriptor file and the application descriptor (in my case, air_updater_flex-app.xml). In both these files you will find a version tag; what you put here needs to be exactly the same.
First, export the existing AIR application for release, and then install it. Now, you are ready to test the update:
To use the update framework with Ajax, you will need the applicationupdater_ui.swf file (the SWC file is used only for the AIR projects created in Flex). Again, I am too lazy to create a UI. And again, you can create the AIR application in your favorite text editor and use the command-line tools to test and package. However, I prefer to use Aptana.
Note: If you don't want to go through step-by-step instructions to create the project, you can use the archive provided with this article, air_update_ajax.zip. To import it in Aptana, choose Import > General > Archive File.
To set up an AIR project in Aptana Studio:
After creating the project, add the external folder updater, the folder that holds the new version of the application and the update descriptor file (see Figure 4 and the associated explanation on how to do this). I will reuse the same folder (c:\htdocs\updater) that I used for the Flex example.
At this point you should see something like the image shown in Figure 8 (my air_update_ajax.html file may differ from yours because I deleted the comments and some unnecessary JavaScript code).
Now you need to copy the Adobe AIR update framework library (applicationupdater_ui.swf ) to your project. To add this library to the application:
head section: <script src="applicationupdater_ui.swf" type="application/x-shockwave-flash"/>
The page should look like this:
<html>
<head>
<title>AIR AJAX Update Example</title>
<link href="sample.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="AIRAliases.js"></script>
<script src="applicationupdater_ui.swf" type="application/x-shockwave-flash"/>
</head>
<body>
</body>
</html>
updateUI object, in the head section of the air_update_ajax.html file:<script>
// instantiate an updater object
var appUpdater = new runtime.air.update.ApplicationUpdaterUI();
function checkUpdate() {
// we set the URL for the update.xml file
appUpdater.updateURL = "http://localhost/updater/update.xml";
//we set the event handlers for INITIALIZED nad ERROR
appUpdater.addEventListener(runtime.air.update.events.UpdateEvent.INITIALIZED, onUpdate);
appUpdater.addEventListener(runtime.flash.events.ErrorEvent.ERROR, onError);
//we can hide the dialog asking for permission for checking for a new update;
//if you want to see it just leave the default value (or set true).
appUpdater.isCheckForUpdateVisible = false;
//if isFileUpdateVisible is set to true, File Update, File No Update,
//and File Error dialog boxes will be displayed
appUpdater.isFileUpdateVisible = false;
//if isInstallUpdateVisible is set to true, the dialog box for installing the update is visible
appUpdater.isInstallUpdateVisible = false;
//we initialize the updater
appUpdater.initialize();
}
function onUpdate(event) {
//starts the update process
appUpdater.checkNow();
}
function onError(event) {
alert(event);
}
</script>
In the code above, the function checkUpdate() is called each time the application is started. Inside this function, you configure the updater object: set up the URL for the update descriptor file, set up the UI to be displayed, and register two listeners for initialized and error events. The last line of this function initializes the updater object.
After the updater object is initialized, the onUpdate() function gets called and the object is ready to take commands. At this point, the code calls the checkNow() method on the updater object to start the update process (if a new version is found on the server).
Lastly, you need to hook up the call to the checkUpdate() function to the onload event of the application:
<body onload="checkUpdate()">
Now that you've finished coding the application, you need to create the code that stays on the server. First create the update.xml file inside the updater folder from the project. Add this code to the file:
<?xml version="1.0" encoding="utf-8"?>
<update xmlns="http://ns.adobe.com/air/framework/update/description/1.0">
<version>2.9</version>
<url>http://localhost/updater/air_updater_ajax.air</url>
<description><![CDATA[
This version has fixes for the
following known issues:
*First issue
*Second issue
]]></description>
</update>
It is important to correctly set the URL to the packaged application using the <url> tag. On my machine the URL to the updater folder is http://localhost/updater/, and because I chose to place the application in the same folder, the URL is http://localhost/updater/air_update_ajax.air.
There are more options you can set in this file; see the AIR_Update_Framework.pdf file that comes with update framework for more details.
With the code in place, you are ready to test it. First, you need to export the application and install it on your machine. Choose Export > Adobe AIR > Adobe AIR Package (deselect from the list updater folder).
Next, install the application on your machine.
To test the first update, you need to create a new (higher) version of the application:
<version> tags to the same value, for example 3.0.
If you develop AIR applications using Flash (that is, not using the Flex framework), you can still use the Adobe AIR update framework. With Flash, however, you can't use the library with the default UI, since this library uses the Flex framework. As a result, there is a little more work needed to implement the update logic and the UI.
If you don't want to create the project step by step, you can use the archive (air_update_flash.zip) provided with this article. You'll still need to extract the applicationupdater.swc file from the update framework archive, and add it to the project paths (see the next section).
Choose File > New > Flash File (Adobe AIR) and then click OK. Next, choose File > Save and type air_update_flash.fla as the name.
To add the applicationupdater.swc file to the project:
To test that the library was added to the project, switch to Source mode and enter the following ActionScript code:
import air.update.ApplicationUpdater;
var appUpdater:ApplicationUpdater = new ApplicationUpdater();
Run the application; if the library has been added to the project you won't see any errors.
Note: I am not a Flash developer, and it is quite possible that someone more experienced with Flash than I am could write code that is more efficient or more elegant.
lblName and lblVersion.
You will use these controls to display the application name the current version.
As I noted earlier, because you are using the update framework without the default UI, you have to implement the UI yourself. To do this, you can create a custom component (a movie clip) named myWindow. You will use this component to draw the content of the pop-up window that will display the various states while updating the application. Because the logic for updating the application resides in a FLA file, you need a way to control this component's appearance from the main application.
package {
public class myWindow extends MovieClip {
}
}
Basically, you set up all the components needed to draw the windows you will show. When you use the component, you can choose which components to show, which components to hide, what the text and labels will be, and so on.
title_1 for the first text box, description_1 for the text area, bar_1 for the progress bar, button_1 and button_2 for the two buttons.package {
import flash.display.MovieClip;
import fl.controls.ProgressBar;
import fl.controls.Button;
import fl.controls.TextArea;
//this class sets the type for the myWindow component
//we use it as a proxy to the UI controls from the myWindow component
//(buttons, labels, text area, or progress bar)
public class myWindow extends MovieClip {
public function set title(text:String):void {
title_1.text = text;
}
public function set description(text:String):void {
description_1.text = text;
}
public function set enableDescription(enable:Boolean):void {
description_1.visible = enable;
}
public function enableBar(enable:Boolean):void {
bar_1.visible = enable;
}
public function get bar():ProgressBar {
return bar_1;
}
public function get buttonLeft():Button {
return button_1;
}
public function get buttonRight():Button {
return button_2;
}
}
}
Now you can access each component from the main application.
import air.update.ApplicationUpdater;
var appUpdater:ApplicationUpdater = new ApplicationUpdater();
Here is the complete code followed by an explanation:
import air.update.ApplicationUpdater;
import air.update.events.StatusFileUpdateEvent;
import air.update.events.StatusUpdateErrorEvent;
import air.update.events.StatusFileUpdateErrorEvent;
import air.update.events.DownloadErrorEvent;
import air.update.events.StatusUpdateEvent;
import air.update.events.UpdateEvent;
import flash.events.ErrorEvent;
import flash.events.MouseEvent;
import flash.desktop.NativeApplication;
import flash.display.NativeWindow;
import flash.display.NativeWindowInitOptions;
import flash.display.NativeWindowSystemChrome;
import flash.display.NativeWindowType;
import flash.display.StageScaleMode;
import flash.display.StageAlign;
import fl.controls.Button;
import Namespace;
import XML;
var appUpdater:ApplicationUpdater = new ApplicationUpdater();
var window:NativeWindow;
var windowContent:myWindow = new myWindow();
var existentListeners:Dictionary = new Dictionary();
//initialize the updater; gets called when the application is loaded
function initializeUpdater():void {
setApplicationNameAndVersion();
appUpdater.updateURL = "http://localhost/updater/update_flash.xml";
//we set the event handlers for INITIALIZED nad ERROR
appUpdater.addEventListener(UpdateEvent.INITIALIZED, onUpdate);
appUpdater.addEventListener(ErrorEvent.ERROR, onError);
appUpdater.addEventListener(StatusUpdateEvent.UPDATE_STATUS, onStatusUpdate);
appUpdater.addEventListener(StatusUpdateErrorEvent.UPDATE_ERROR, onStatusUpdateError);
appUpdater.addEventListener(ProgressEvent.PROGRESS, onDownloadProgress);
appUpdater.addEventListener(UpdateEvent.DOWNLOAD_COMPLETE, onDownloadComplete);
appUpdater.addEventListener(DownloadErrorEvent.DOWNLOAD_ERROR, onDownloadError);
//initialize the updater
appUpdater.initialize();
}
//listener for INITIALIZED event of the applicationUpdater;
function onUpdate(event:UpdateEvent):void {
//start the process of checking for a new update and to install
appUpdater.checkNow();
}
//Handler function for error events triggered by the ApplicationUpdater.initialize
function onError(event:ErrorEvent):void {
trace(event);
createWindow();
displayWindowError(event.errorID, event.text);
}
//handler function for StatusUpdateEvent.UPDATE_STATUS
//this is called after the update descriptor was downloaded and interpreted successfuly
function onStatusUpdate(event:StatusUpdateEvent):void {
trace(event);
//prevent the default (start downloading the new version)
event.preventDefault();
createWindow();
windowContent.bar.visible = false; //hide the progress bar
//create the window for displaying Update available
if (event.available) {
windowContent.title = "Update Available";
windowContent.enableDescription = true;
windowContent.description = event.version + " " + event.details[0][1];
windowContent.buttonLeft.label = "Update";
windowContent.buttonRight.label = "Cancel";
addEventToButton(windowContent.buttonLeft, MouseEvent.CLICK, startDownload);
addEventToButton(windowContent.buttonRight, MouseEvent.CLICK, closeWindow);
//we don't have an update, so display this information
} else {
windowContent.title = "No Update Available";
windowContent.enableDescription = false;
windowContent.buttonLeft.visible = false;
windowContent.buttonRight.label = "Close";
addEventToButton(windowContent.buttonRight, MouseEvent.CLICK, closeWindow);
}
}
//error listener for an error when the updater could not download or
//interpret the update descriptor file.
function onStatusUpdateError(event:StatusUpdateErrorEvent):void
{
createWindow();
displayWindowError(event.subErrorID, event.text);
}
//error listener for DownloadErrorEvent. Dispatched if there is an error while connecting or
//downloading the update file. It is also dispatched for invalid HTTP statuses
//(such as "404 - File not found").
function onDownloadError(event:DownloadErrorEvent):void {
createWindow();
displayWindowError(event.subErrorID, event.text);
}
//start the download of the new version
function startDownload(event:MouseEvent):void {
appUpdater.downloadUpdate();
createWindow();
windowContent.bar.visible = true;
windowContent.bar.setProgress(0, 100);
}
//listener for the ProgressEvent when a download of the new
version is in progress
function onDownloadProgress(event:ProgressEvent):void {
windowContent.bar.setProgress(event.bytesLoaded, event.bytesTotal);
}
//listener for the complete event for downloading the application
//just close the window; the downloaded version will be automatically installed,
//and then the application gets restarted
function onDownloadComplete(event:UpdateEvent):void {
closeWindow(null);
}
//sets the state of the window in error display mode
function displayWindowError(errorId:int, errorText:String):void
{
windowContent.title = "Error";
windowContent.enableDescription = true;
windowContent.description = "Error ID: " + errorId + ". " + errorText;
windowContent.buttonLeft.visible = false;
windowContent.buttonRight.label = "Close";
windowContent.bar.visible = false;
addEventToButton(windowContent.buttonRight, MouseEvent.CLICK, closeWindow);
}
//create a window using NativeWindow, and as a content myWindow
class
function createWindow():void {
if (window == null) {
var options:NativeWindowInitOptions = new NativeWindowInitOptions();
options.systemChrome = NativeWindowSystemChrome.STANDARD;
options.type = NativeWindowType.NORMAL;
window = new NativeWindow(options);
window.x = 300;
window.y = 200;
window.stage.stageHeight = 230;
window.stage.stageWidth = 450;
window.stage.scaleMode = StageScaleMode.NO_SCALE;
window.stage.align = StageAlign.TOP_LEFT;
window.stage.addChild(windowContent);
windowContent.bar.visible = false;
}
window.alwaysInFront = true;
window.visible = true;
}
//close the window
function closeWindow(event:Event):void {
window.close();
}
//hide the window
function hideWindow():void {
window.visible = false;
}
//sets the application name and version in the main window
function setApplicationNameAndVersion():void {
var appXML:XML = NativeApplication.nativeApplication.applicationDescriptor;
var ns:Namespace = appXML.namespace();
lblVersion.text = appXML.ns::version;
lblName.text = appXML.ns::name;
}
//add to the given button, the listener for given type (actually we use only the type MouseEvent.CLICK).
//we use a dictionary to store for each button the listener registered.
//when this function gets called, first we remove any registered listener. Next we register the listener
//on the button, and next we save to dictionary.
function addEventToButton(button:Button, type:String, listener:Function):void
{
//remove existent listneres
if (existentListeners[button] != null) {
var arr:Array = existentListeners[button] as Array;
button.removeEventListener(type, arr[0]);
}
existentListeners[button] = [];
button.addEventListener(type, listener);
existentListeners[button][0] = listener;
button.visible = true;
}
initializeUpdater();
//initialize the updater
This code does the following:
NativeWindow instance and a myWindow instance (the component you created earlier) to draw the pop-up window (see the function createWidow() in the code).initializeUpdater() is called once the application is loaded. This function initializes the update framework object (appUpdater), sets the URL for the update descriptor file (on my machine the path is http://localhost/updater/update_flash.xml), and registers listeners for different events on the update object. While I chose a minimal implementation (I intend to show a window if an update is available or not, to display the window while the update is downloaded, and to display an error window if something goes wrong), you can implement more windows (see the documentation for more details).setApplicationNameAndVersion() is called from initializeUpdater() and sets the application name and version in the UI in the main application window.createWindow), and functions to hide and close the window.You have almost all the bits in place. You have to write the update descriptor file, and set the URL of the applicationUpdater (this is set in the initializeUpdater() function) to point to this file.
<?xml version="1.0" encoding="utf-8"?>
<update xmlns="http://ns.adobe.com/air/framework/update/description/1.0">
<version>1.2</version>
<url>http://localhost/updater/air_update_flash.air</url>
<description><![CDATA[
This version has fixes for the following known issues:
*First issue
*Second issue
]]></description>
</update>
AIR 2.5 introduces a number of changes for the Update framework. Although the general principles and worflow remain the same, you'll notice the following differences when you use the update framework with AIR 2.5 or later:
Here is an an example of the new update descriptor file:
<?xml version="1.0" encoding="utf-8"?>
<update xmlns="http://ns.adobe.com/air/framework/update/description/2.5">
<versionNumber>0.9.2</versionNumber>
<versionLabel>Beta 2</versionLabel>
<url>http://localhost/updater/AIRUpdater.air</url>
<description><![CDATA[
This version has fixes for the following knowns issues:
*First issue
*Second issue
]]></description>
</update>
If you forget to update the update descriptor file namespace to 2.5, then you will get this error: Error# 16831 (see Figure 18).
If you forget to use the <versionNumber> tag instead of <version> in the update descriptor file and the namespace is set to 2.5, you will get this error: Error# 16816 (see Figure 19).
If you have an application created with a version of AIR that is older than 2.5 and you want to update the application to AIR 2.5 or later, you have to implement a two-step update process:
Here is the breakdown of this process:
Suppose the current version of your application is 2.0 and that it is built using Adobe AIR 1.5; the first thing you want to do is to create an interim version of the application that uses the update framework from AIR 2.5.
<?xml version="1.0" encoding="utf-8"?>
<update xmlns="http://ns.adobe.com/air/framework/update/description/1.0">
<version>2.1</version>
<url>http://localhost/updater/air_update_flex.air</url>
<description><![CDATA[
]]></description>
</update>
appUpdater.updateURL = "http://localhost/updater/update_to_2_5.xml";
//previous update descriptor file
//appUpdater.updateURL = "http://localhost/updater/update.xml";
<?xml version="1.0" encoding="utf-8"?>
<update xmlns="http://ns.adobe.com/air/framework/update/description/1.0">
<version>2.5</version>
<url>http://localhost/updater/air_update_flex-2.5.air</url>
<description><![CDATA[
]]></description>
</update>
Next, you need to create the final version of your application, the one that is uses the AIR 2.5 SDK and it is compiled with this version of the SDK. From the point of view of the update process there are five steps:
<?xml version="1.0" encoding="utf-8"?>
<update xmlns="http://ns.adobe.com/air/framework/update/description/2.5">
<versionNumber>2.5</versionNumber>
<versionLabel>Version for 2.5</versionLabel>
<url>http://localhost/updater/air_update_flex-2.5.air</url>
<description><![CDATA[
]]></description>
</update>
updateURL property to point to this new update descriptor file.appUpdater.updateURL = "http://localhost/updater/update_2_5_final.xml";
Once you've done this, you should be able to compile the project. For this example, the version will be saved as air_update_flex-2_5.air file.
After you have created all the files you need, you will proced to uploading them to your server. First upload the application files (in this example air_update_flex.air and air_update_flex-2_5.air) and then the update descriptor files (update.xml, update_to_2_5.xml, and update_2_5_final.xml).
By respecting this order, you ensure that no user will experience a break during the update process due to missing files or wrong versions.
The Adobe AIR update framework enables you to add a very important and useful feature to your applications: the ability to push updates to your users very easily. The update framework supports Flex, Ajax, and Flash, so you're covered no matter what technology you prefer for developing AIR applications.
For more AIR resources, visit the AIR Developer Center. Also, take time to read the documentation that comes with the framework. You'll discover how flexible it is, and how you can customize it to meet your needs.