Chapter 16. Application Updates

In the past when a bug was found or an enhancement was needed, developers working on Internet-based applications enjoyed the simplicity of quickly and seamlessly updating the application running on their servers. This metaphor changes when developing applications for the desktop on Adobe AIR; under this model, updates now need to be distributed to the complete user base.

Now that your application resides in an environment you do not “own,” you must take additional measures. To maintain the ability to perform seamless updates, you must include update procedures in your application before it goes into the wild so that it can “phone home” to get updates if and when needed.

Creating Applications with Update Capabilities

Problem

You are creating an AIR application that you plan to distribute and want to build in the ability to upgrade your users to new versions quickly.

Solution

Use the Adobe AIR Update Framework library, which is new to AIR 1.5 and makes it easier for applications to handle the various update scenarios that may arise.

Discussion

The Adobe AIR Update Framework library offers you all the functionality you need to create AIR applications that can remotely update themselves. The framework retrieves specifics about the available update from a remote XML file. This file contains versioning information, as well as the location of the update files. This file is accessed whenever the application makes a request to check for an update. Consider the following example called update.xml:

<?xml version="1.0" encoding="utf-8"?>
<update xmlns="http://ns.adobe.com/air/framework/update/description/1.0">
    <version>1.1</version>
    <url>http://mydomain.com/air/myapplication.air</url>
    <description><![CDATA[ Various Bug Fixes ]></description>
</update>

The nodes of this XML file are as follows:

  • version: The newest version available

  • url: The URL to download the AIR package

  • description: Additional text to provide the user with a description of what the update contains

You can also provide language-specific descriptions by adding a text subnode to the description node. Here’s an example of this:

<description>
    <text xml:lang="en">English description</text>
    <text xml:lang="it">Italian description</text>
</description>

The Adobe AIR Update Framework supports a second, optional XML configuration file packaged with the application that you can use to set additional configuration properties that dictate the operations of the updating process at runtime. These configuration properties will instruct the framework on which dialog boxes to show to the user during the update process. You also can choose to set these properties manually on the ApplicationUpdaterUI class, but a best practice would be to include an XML file, such as updaterConfig.xml shown here, within your application distribution, so you can change configuration information within the XML file without having to recompile the application:

<?xml version="1.0" encoding="utf-8"?>
 <configuration xmlns="http://ns.adobe.com/air/framework/update/configuration/1.0">
   <url>http://mydomain.com/myairapp/update.xml</url>
   <delay>1</delay>
   <defaultUI>
       <dialog name="checkForUpdate" visible="true" />
       <dialog name="downloadUpdate" visible="true" />
       <dialog name="downloadProgress" visible="true" />
       <dialog name="installUpdate" visible="true" />
   </defaultUI>
</configuration>

The nodes of this file are as follows:

  • url: This is the path to the update.xml file (the remote XML file containing application version information).

  • delay: This is the interval in which the Adobe AIR Update Framework checks whether updates are available. This is configured in days, so 1 represents one day. A value of .04 is approximately one hour.

  • defaultUI: The dialog nodes within the defaultUI node allow you to show or hide specific sections of the Adobe AIR Update Framework user interface. By default, they will all show. These dialog boxes are shown in Figure 16-1Figure 16-4 later in this chapter.

Because you will be using the built-in updater interface of the ApplicationUpdaterUI class, you must make sure you have applicationupdater_ui.swc linked to your project.

To use this updater class, you create an instance of the ApplicationUpdaterUI class and set the path to the updaterConfig.xml file. Finally, you need to initialize the updater. The following examples show how to create an instance of the ApplicationUpdaterUI class, set the path to the updaterConfig.xml file, and initialize the updater. Consult the version appropriate for your application language.

Upon initialization of the ApplicationUpdaterUI instance, the UpdateEvent.INITIALIZED event will fire, and you can check several properties of the instance. These properties include the following:

  • isFirstRun: This is true only if this is the first run since an update has occurred.

  • previousVersion: This contains the previous version information only if isFirstRun is true.

  • currentVersion: This always contains the version information of the currently running application.

Because you set the delay to 1 in updaterConfig.xml, the updater will not automatically check until the application has been open for a full day. So, the updater also provides a way for you to manually check for updates by calling the checkNow method.

The ApplicationUpdaterUI class handles all the functionality of the update process. For information on how to create your own updater with a custom interface, please check out Creating Custom Update Interfaces for Applications with Update Capabilities.

Flex/ActionScript

This example sets the path to the configuration file, instantiates an ApplicationUpdaterUI instance, listens for the UpdateEvent.INITIALIZED event, and then initializes the updater on creationComplete of the application. Finally, when the initialize handler updaterInitialized is called, the event’s properties are displayed onscreen.

Note

You need to have the applicationupdater_ui.swc file included in your Flex build path. This file can be found in the frameworks directory of the Adobe AIR 1.5 SDK.

<?xml version="1.0" encoding="utf-8"?>
<mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute"
     creationComplete="init()">
    <mx:Script>
    <![CDATA[

    import air.update.events.UpdateEvent;
    import air.update.ApplicationUpdaterUI;

    private var updater:ApplicationUpdaterUI = new ApplicationUpdaterUI();

    private function init():void{
        updater.configurationFile = new File("app:/config/updaterConfig.xml");
        updater.addEventListener(UpdateEvent.INITIALIZED, updaterInitialized);
        updater.initialize();
    }

    private function updaterInitialized(event:UpdateEvent):void{
        isFirstRun.text = event.target.isFirstRun;
        previousVersion.text = event.target.previousVersion;
        currentVersion.text = event.target.currentVersion;
    }

    ]]>
    </mx:Script>

    <mx:Canvas width="300" height="200" horizontalCenter="0" verticalCenter="0">
        <mx:Label text="isFirstRun:" x="80" y="45"/>
        <mx:Text id="isFirstRun" x="180" y="45"/>
        <mx:Label text="previousVersion:" x="78" y="75"/>
        <mx:Text id="previousVersion" x="180" y="75"/>
        <mx:Label text="currentVersion:" x="78" y="105"/>
        <mx:Text id="currentVersion" x="180" y="105"/>
        <mx:Button click="updater.checkNow();" label="Check for Update"
        x="88" y="135"/>
    </mx:Canvas>

</mx:WindowedApplication>

JavaScript

This example sets the path to the configuration file, instantiates an ApplicationUpdaterUI instance, listens for the UpdateEvent.INITIALIZED event, and then initializes the updater when the onLoad event of the body tag is called. Finally, when the updaterInitialized method is called, the event’s properties are displayed onscreen.

Note

You need to have the applicationupdater_ui.swf file included via a script as an include to your file, as shown next. This can be found in the frameworks directory of the AIR 1.5 SDK.

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN">
    <html>
    <head>
    <title>Update framework Sample</title>
    <script src="AIRAliases.js" type="text/javascript" charset="utf-8">
    </script>
    <script src="applicationupdater_ui.swf" type="application/x-shockwave-flash">
    </script>
    <script>
    var updater;
    function initialize() (
        updater  = new runtime.air.update.ApplicationUpdaterUI();
        updater.configurationFile = new   air.File("app:/config/updaterConfig.xml");              
        updater.addEventListener(
                        runtime.air.update.events.UpdateEvent.INITIALIZED,                                      
                        function(event){updaterInitialized()}
          );
          updater.initialize();
    }

    function updaterInitialized(event) (
        document.getElementById('isFirstRun').innerHTML =
                                updater.isFirstRun;
        document.getElementById('previousVersion').innerHTML =
                                updater.previousVersion;
        document.getElementById('currentVersion').innerHTML =
                                updater.currentVersion;
    }
    </script>
    </head>

    <body onLoad="initialize()">
        isFirstRun: <span id="isFirstRun"></span><br/><br/>
        previousVersion:<span id="previousVersion"></span><br/><br/>
        currentVersion: <span id="currentVersion"></span><br/><br/>
        <input type="button" onClick="updater.checkNow()"
            value="Check for updates" />
    </body>
</html>

In this recipe, the default ApplicationUpdaterUI class was used. Figure 16-1 through Figure 16-4 show various screens of the default user interface.

Specifically, Figure 16-1 shows the dialog box presented to the user when checkForUpdate is set to true in updaterConfig.xml.

Step 1 of the default ApplicationUpdaterUI class
Figure 16-1. Step 1 of the default ApplicationUpdaterUI class

Figure 16-2 shows the dialog box presented to the user when downloadUpdate is set to true in updaterConfig.xml.

Step 2 of the default ApplicationUpdaterUI class
Figure 16-2. Step 2 of the default ApplicationUpdaterUI class

Figure 16-3 shows the dialog box presented to the user when downloadProgress is set to true in updaterConfig.xml.

Figure 16-4 shows the dialog box presented to the user when installUpdate is set to true in updaterConfig.xml.

Creating Custom Update Interfaces for Applications with Update Capabilities

Problem

You want to use the Adobe AIR Update Framework; however, your client requires specific information to appear in the updater dialog box.

Solution

Use the Adobe AIR Update Framework’s applicationupdater.swc/applicationupdater.swf file, which does not include a user interface for the updater dialog box, and create a custom updater interface.

Step 3 of the default ApplicationUpdaterUI class
Figure 16-3. Step 3 of the default ApplicationUpdaterUI class
Step 4 of the default ApplicationUpdaterUI class
Figure 16-4. Step 4 of the default ApplicationUpdaterUI class

Discussion

Creating Applications with Update Capabilities demonstrated how to use the Adobe AIR Update Framework with its built-in dialog boxes. By following those same steps and listening for additional events, you can use the ApplicationUpdater class and customize your own update dialog boxes.

As Creating Applications with Update Capabilities mentioned, you can configure the Adobe AIR Update Framework in two ways. Creating Applications with Update Capabilities used an XML file (updaterConfig.xml) that included information about delay timing, the update URL path, and user interface settings. You can certainly use an XML configuration file to override the built-in dialog box settings. However, this recipe demonstrates the other way of configuring the updater, which is through direct property settings.

To build a custom experience, the examples demonstrated later in this recipe rely on events being broadcast from the ApplicationUpdater class. These events and their properties are outlined here:

UpdateEvent.INITIALIZED

isFirstRun: This is true only if an update has just occurred.

previousVersion: This has a value only if isFirstRun is true.

currentVersion: This always contains the version information of the currently running application.

StatusUpdateEvent.UPDATE_STATUS

available: This is true if the version property in the update.xml file is different from the version of the running application.

version: This holds the value of the version property in the update.xml file.

details: This holds the value of the details property in the update.xml file.

StatusUpdateErrorEvent.UPDATE_ERROR

This event has no properties and is dispatched only when an error occurs while the Adobe AIR Update Framework is trying to read the update.xml file.

UpdateEvent.DOWNLOAD_START

This event has no properties; it fires when the download starts.

ProgressEvent.PROGRESS

This event is a standard ProgressEvent that contains the standard bytesLoaded and bytesTotal properties that you use to display progress on any upload or download.

UpdateEvent.DOWNLOAD_COMPLETE

This event is dispatched after the download has completed and has no properties. After the download completes, the default behavior is to automatically start the install process. This event allows you to stop the automatic install.

DownloadErrorEvent.DOWNLOAD_ERROR

subErrorID: This is broadcast when an error occurs during the download of the new AIR file. It also contains the standard errors of its parent, the ErrorEvent class.

Note

This is not the complete list of events available for the Adobe AIR Update Framework. It does include all the events necessary to create the custom updater interface in the following examples.

With an understanding of the events that will be listened for, you’re ready to investigate the flow of the update process.

Flex/ActionScript

This sample consists of two files: the main MXML file based on the WindowedApplication file and a Window component that acts as the user interface for the update process. The Window component is referred to as UpdateWindow throughout the rest of this recipe and resides in the root directory along with the main MXML file. The main application window simply contains a single Button component that, when clicked, launches a new window. The code for the main application window is as follows:

<?xml version="1.0" encoding="utf-8"?>
<mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute"
   title="Adobe AIR Update Framework">

    <mx:Script>
        <![CDATA[

            private function openUpdateWindow():void{
                var updateWindow:UpdateWindow = new UpdateWindow();
                updateWindow.open();
            }
        ]]>
    </mx:Script>
    <mx:Button click="openUpdateWindow()" label="Open Update Window"
        horizontalCenter="0" verticalCenter="0"/>

</mx:WindowedApplication>

UpdateWindow is the guts of this example because it contains all the methods and event listeners to handle each step of the update process. This component contains five different states that contain the controls and feedback to give the user full control over the update. Each following section will contain only the methods necessary to interact with the Adobe AIR Update Framework. The full source code for UpdateWindow is available later in this recipe.

Upon creationComplete of the window, the init method is called. This method creates a new instance of the ApplicationUpdater class, sets the delay property of the updater to 0, sets the updater’s updateURL, adds six different event listeners, and then calls the initialize method on new instance of the ApplicationUpdater class.

The UpdateWindow defaults to the Main state, which shows the user information about the currently installed application including the updater’s isFirstRun, previousVersion, and currentVersion properties. It also contains a Button component, which allows the user to check to see whether an update is available.

Because the delay property is set to 0 in this example, the updater never automatically checks for an update. When the user clicks the Check for Update button, the updater’s checkNow method is called. Figure 16-5 shows the results of the checkNow method.

private function init():void{
    updater = new ApplicationUpdater();
    updater.delay = 0;
    updater.updateURL = "http://mydomain.com/myairapp/update.xml";
    updater.addEventListener(UpdateEvent.INITIALIZED,
                             updaterInitialized);
    updater.addEventListener(StatusUpdateEvent.UPDATE_STATUS,
                             statusUpdate);
    updater.addEventListener(StatusUpdateErrorEvent.UPDATE_ERROR,
                             statusUpdateError);
    updater.addEventListener(UpdateEvent.DOWNLOAD_START,
                             downloadStarted);
    updater.addEventListener(ProgressEvent.PROGRESS,
                             downloadProgress);
    updater.addEventListener(UpdateEvent.DOWNLOAD_COMPLETE,
                             downloadComplete);
    updater.addEventListener(DownloadErrorEvent.DOWNLOAD_ERROR,
                             downloadError);
    updater.initialize();
}

private function updaterInitialized(event:UpdateEvent):void{
    isFirstRun.text = event.target.isFirstRun;
    previousVersion.text = event.target.previousVersion;
    currentVersion.text = event.target.currentVersion;
}
UpdateWindow shows the updater’s properties for the first run and the current version.
Figure 16-5. UpdateWindow shows the updater’s properties for the first run and the current version.

The checkNow method dispatches the StatusUpdateEvent.UPDATE_STATUS event, which then calls the statusUpdate method. If the available property of this event is true, the state of the UpdateWindow is set to Available. If there is no update available, the state is set to None, and the user is shown a message stating this.

private function statusUpdate(event:StatusUpdateEvent):void{
    event.preventDefault();
    if(event.available){
        currentState="Available";
        version.text =  event.version;
        details.text = String(event.details);
    } else {
        currentState="None";
    }
}

If an update is available, the user sees the Available state, information about the update is displayed, and the user can choose to cancel or download the update (Figure 16-6).

UpdateWindow shows that an update is available.
Figure 16-6. UpdateWindow shows that an update is available.

If the user clicks the Download Now button, the downloadUpdate method is called on the ApplicationUpdater instance. The ApplicationUpdater instance then attempts to download the new AIR file from the URL that has been supplied in the update.xml file. If the ApplicationUpdater instance is able to begin the download, the UpdateEvent.DOWNLOAD_START event is dispatched, and the downloadStarted method is called, which changes UpdateWindow to the Downloading state. If the ApplicationUpdater instance cannot begin the download, the DownloadErrorEvent.DOWNLOAD_ERROR event is dispatched, which calls the downloadError method. The downloadError method simply alerts the user that a problem occurred when attempting the download.

Assuming that the download has started correctly, the ProgressEvent.PROGRESS event begins to be dispatched as the file is downloading. This event calls the downloadProgress method, which updates a progress bar that is part of the Downloading state. Figure 16-7 shows the download progress being displayed to the user.

private function downloadStarted(event:UpdateEvent):void{
    currentState="Downloading";
}

private function downloadError(event:DownloadErrorEvent):void{
    currentState="";
    Alert.show("An error has occurred while downloading the update",
                              "DownloadErrorEvent.DOWNLOAD_ERROR");
    close();
}

private function downloadProgress(event:ProgressEvent):void{
    dBar.setProgress(event.bytesLoaded, event.bytesTotal);
}
UpdateWindow shows the download progress.
Figure 16-7. UpdateWindow shows the download progress.

Upon completion of the download, the UpdateEvent.DOWNLOAD_COMPLETE event is dispatched, which calls the downloadComplete method. If this event is ignored, the ApplicationUpdater automatically begins the install of the new AIR application. In this example, the preventDefault method is called on the UpdateEvent, and the state of UpdateWindow is set to InstallNow. The preventDefault method halts the automatic install by the ApplicationUpdater instance (Figure 16-8).

private function downloadComplete(event:UpdateEvent):void{
    event.preventDefault();
    currentState="InstallNow";
}

The InstallNow state gives the user the option to cancel or install the update. If the user chooses to install the update, the installUpdate method is called on the ApplicationUpdater instance. At this time, the application closes, installs the new AIR application, and relaunches. Upon relaunch, if the user launches UpdateWindow, the isFirstRun property shows as true, and the new version information is displayed (Figure 16-9).

UpdateWindow asks the user whether they want to install the update.
Figure 16-8. UpdateWindow asks the user whether they want to install the update.
UpdateWindow shows that the first run is now true and the new version is installed.
Figure 16-9. UpdateWindow shows that the first run is now true and the new version is installed.

The full source code for UpdateWindow is as follows:

<?xml version="1.0" encoding="utf-8"?>
<mx:Window xmlns:mx="http://www.adobe.com/2006/mxml" width="400" height="300"
    creationComplete="init()" layout="absolute" currentState="Main"
    title="Update Window">

    <mx:states>
          <mx:State name="Available">
               <mx:AddChild position="lastChild">
                     <mx:Text id="version" x="181.5" y="64"/>
               </mx:AddChild>
               <mx:SetProperty target="{mainTitle}" name="text"
                     value="There is an update available"/>
               <mx:AddChild position="lastChild">
                     <mx:Label x="98.5" y="64" text="New version:"/>
               </mx:AddChild>
               <mx:AddChild position="lastChild">
                     <mx:Label x="98" y="90" text="Details:"/>
               </mx:AddChild>
               <mx:AddChild position="lastChild">
                     <mx:TextArea x="181" y="89" id="details" width="174"
                          height="126" editable="false"/>
               </mx:AddChild>
               <mx:AddChild position="lastChild">
                     <mx:Button x="181" y="223" label="Cancel" click="close()"/>
               </mx:AddChild>
               <mx:AddChild position="lastChild">
                     <mx:Button x="246" y="223" label="Download Now"
                          click="updater.downloadUpdate();"/>
               </mx:AddChild>
          </mx:State>
          <mx:State name="Downloading">
               <mx:SetProperty target="{mainTitle}" name="text"
                     value="Downloading Update"/>
               <mx:AddChild position="lastChild">
                     <mx:ProgressBar x="99" y="78" id="dBar" mode="manual"/>
               </mx:AddChild>
          </mx:State>
          <mx:State name="None">
               <mx:AddChild position="lastChild">
                     <mx:Button label="Close" click="close();"
                          y="81" horizontalCenter="0"/>
               </mx:AddChild>
               <mx:SetProperty target="{mainTitle}" name="text"
                     value="You already have the most current version"/>
          </mx:State>
          <mx:State name="InstallNow">
               <mx:SetProperty target="{mainTitle}" name="text"
                     value="Would you like to install the update now?"/>
               <mx:AddChild position="lastChild">
                     <mx:Button x="190.5" y="94"
                          label="Install Now" click="updater.installUpdate();"/>
               </mx:AddChild>
               <mx:AddChild position="lastChild">
                     <mx:Button x="117.5" y="94" label="Cancel" click="close()"/>
               </mx:AddChild>
          </mx:State>
          <mx:State name="Main">
               <mx:AddChild position="lastChild">
                     <mx:Label x="90" y="90" text="First Run:"/>
               </mx:AddChild>
               <mx:AddChild position="lastChild">
                     <mx:Label x="90" y="120" text="Previous Version:"/>
               </mx:AddChild>
               <mx:AddChild position="lastChild">
                     <mx:Label x="90" y="150" text="Current Version:"/>
               </mx:AddChild>
               <mx:AddChild position="lastChild">
                     <mx:Text x="200" y="90" id="isFirstRun"/>
               </mx:AddChild>
               <mx:AddChild position="lastChild">
                     <mx:Text x="200" y="120" id="previousVersion"/>
               </mx:AddChild>
               <mx:AddChild position="lastChild">
                     <mx:Text x="200" y="150" id="currentVersion"/>
               </mx:AddChild>
               <mx:AddChild position="lastChild">
                     <mx:Button y="190" label="Check for Update" horizontalCenter="0"
                          click="updater.checkNow()"/>
               </mx:AddChild>
          </mx:State>
    </mx:states>

    <mx:Script>
          <![CDATA[

               import mx.controls.Alert;
               import air.update.events.StatusUpdateErrorEvent;
               import air.update.events.StatusUpdateEvent;
               import air.update.events.DownloadErrorEvent;
               import air.update.events.UpdateEvent;
               import air.update.ApplicationUpdater;

               public var updater:ApplicationUpdater

               private function init():void{
                     updater = new ApplicationUpdater();
                     updater.delay = 0;
                     updater.updateURL = "http://mydomain.com/myairapp/update.xml";
                     updater.addEventListener(UpdateEvent.INITIALIZED,
                                                    updaterInitialized);
                     updater.addEventListener(StatusUpdateEvent.UPDATE_STATUS,
                                                    statusUpdate);
                     updater.addEventListener(StatusUpdateErrorEvent.UPDATE_ERROR,
                                                    statusUpdateError);
                     updater.addEventListener(UpdateEvent.DOWNLOAD_START,
                                                    downloadStarted);
                     updater.addEventListener(ProgressEvent.PROGRESS,
                                                    downloadProgress);
                     updater.addEventListener(UpdateEvent.DOWNLOAD_COMPLETE,
                                                    downloadComplete);
                     updater.addEventListener(DownloadErrorEvent.DOWNLOAD_ERROR,
                                                    downloadError);
                     updater.initialize();
               }

               private function updaterInitialized(event:UpdateEvent):void{
                     isFirstRun.text = event.target.isFirstRun;
                     previousVersion.text = event.target.previousVersion;
                     currentVersion.text = event.target.currentVersion;
               }


               private function statusUpdate(event:StatusUpdateEvent):void{
                     event.preventDefault();
                     if(event.available){
                          currentState="Available";
                          version.text =  event.version;
                          details.text = String(event.details);
                     } else {
                          currentState="None";
                     }
               }


            private function statusUpdateError(event:StatusUpdateErrorEvent):void{
               currentState="";
                     Alert.show("An error has occurred while checking for updates",
                                "StatusUpdateEvent.UPDATE_STATUS");
                     close();
               }

            private function downloadStarted(event:UpdateEvent):void{
                     currentState="Downloading";
               }

               private function downloadError(event:DownloadErrorEvent):void{
                     currentState="";
                     Alert.show("An error has occurred while downloading the update",
                                "DownloadErrorEvent.DOWNLOAD_ERROR");
                     close();
               }

               private function downloadProgress(event:ProgressEvent):void{
                     dBar.setProgress(event.bytesLoaded, event.bytesTotal);
               }

               private function downloadComplete(event:UpdateEvent):void{
                     event.preventDefault();
                     currentState="InstallNow";
               }

          ]]>
    </mx:Script>

    <mx:Label y="24" text="Adobe AIR Update Framework"
          horizontalCenter="0" width="100%"
          textAlign="center" fontWeight="bold" fontSize="13" id="mainTitle"/>

</mx:Window>

JavaScript

This sample consists of two files: the main Index.html file that acts as the main application window and a Window component (called UpdateWindow throughout this recipe) that contains the UpdateWindow.html file and acts as the user interface for the update process. The main application window contains a single Button that, when clicked, launches a new window. The code for Index.html file is as follows:

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN">
    <html>
    <head>
    <title>Adobe AIR Update Framework</title>
    <script>
          function openUpdateWindow(){
               var updateWindow = window.open('UpdateWindow.html',null,
                                     'width = 220, height = 250'),
         }
    </script>
    </head>
    <body>
    <div align="center">
         <input type="button" onClick="openUpdateWindow()"
               value="Open Update Window" />
   </div>
    </body>
</html>

UpdateWindow is the guts of this example because it contains all the methods and event listeners to handle each step of the update process. This file contains five different divs that contain the controls and feedback to give the user full control over the update.

When the UpdateWindow.html file loads into Window, the body tag’s onLoad event calls the initialize method, which creates a new instance of the ApplicationUpdater class. It also sets the delay property of the updater to 0, sets the updater’s updateURL, adds six different event listeners, and then calls the initialize method on the new instance of the ApplicationUpdater.

UpdateWindow defaults to showing only the Main div, which shows the user information about the currently installed application including the updater’s isFirstRun, previousVersion, and currentVersion properties. It also contains a Button, which allows the user to check to see whether an update is available.

Because the delay was set to 0 in this example, the updater will never automatically check for an update. When the user clicks the Check for Update button, the updater’s checkNow method is called (Figure 16-10).

UpdateWindow shows the updater’s properties for the first run and the current version.
Figure 16-10. UpdateWindow shows the updater’s properties for the first run and the current version.

The checkNow method dispatches the StatusUpdateEvent.UPDATE_STATUS event, which then calls the statusUpdate method. If the available property of this event is true, the state of the UpdateWindow is set to Available. If there is no update available, the state is set to None, and the user is shown a message stating this.

If an update is available and the user is now seeing only the Available div, information about the update is displayed, and the user is given the option to cancel or download the update (Figure 16-11).

UpdateWindow shows that an update is available.
Figure 16-11. UpdateWindow shows that an update is available.

If the user has clicks the Download Now button, the downloadUpdate method is called on the ApplicationUpdater. The ApplicationUpdater then attempts to download the new AIR file from the URL that has been supplied in the update.xml file. If the ApplicationUpdater is able to begin the download, the UpdateEvent.DOWNLOAD_START event is dispatched, and the downloadStarted method is called, which changes the UpdateWindow component to show only the Downloading div. If the ApplicationUpdater cannot begin the download, the DownloadErrorEvent.DOWNLOAD_ERROR event is dispatched, which calls the downloadError method. The downloadError method simply alerts the user that a problem occurred when attempting the download.

Assuming that the download has started correctly, the ProgressEvent.PROGRESS event begins to be dispatched as the file is downloading. This event calls the downloadProgress method, which updates the Downloading div and shows the percent of download completed (Figure 16-12).

UpdateWindow shows the download progress.
Figure 16-12. UpdateWindow shows the download progress.

Upon completion of the download, the UpdateEvent.DOWNLOAD_COMPLETE event is dispatched, which calls the downloadComplete method. If this event is ignored, the ApplicationUpdater automatically begins the install of the new AIR application. In this example, the preventDefault method is called on the UpdateEvent, and the UpdateWindow is set to show only the InstallNow div (Figure 16-13). The preventDefault method will halt the automatic install by the ApplicationUpdater.

UpdateWindow asks user whether they want to install the update.
Figure 16-13. UpdateWindow asks user whether they want to install the update.

The InstallNow state gives the user the option to cancel or install the update. If the user chooses to install, the installUpdate method is called on the ApplicationUpdater. The application closes, installs the new AIR application, and relaunches. Upon relaunch, if the user launches UpdateWindow, the isFirstRun property shows as true, and the new version information is displayed (Figure 16-14).

UpdateWindow shows that the first run is now true and the new version is installed.
Figure 16-14. UpdateWindow shows that the first run is now true and the new version is installed.

The full source code for UpdateWindow (UpdateWindow.html) file is as follows:

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN">
    <html>
    <head>
    <title>Update Window</title>
    <script src="AIRAliases.js" type="text/javascript" charset="utf-8">
    </script>
    <script src="applicationupdater.swf" type="application/x-shockwave-flash">
    </script>
    <script>

    var updater;

    function showDiv(divName){
        document.getElementById('Available').style.visibility = 'hidden';
        document.getElementById('Downloading').style.visibility = 'hidden';
        document.getElementById('InstallNow').style.visibility = 'hidden';
        document.getElementById('Main').style.visibility = 'hidden';
        document.getElementById('None').style.visibility = 'hidden';
        document.getElementById(divName).style.visibility = 'visible';
    }

    function initialize(){
        showDiv('Main'),
        updater = new runtime.air.update.ApplicationUpdater();
        updater.delay=0;
        updater.updateURL = "http://mydomain.com/myairap/update.xml";
    
    updater.addEventListener(runtime.air.update.events.UpdateEvent.INITIALIZED,
                             function(event){updaterInitialized(event);}
                             );

    updater.addEventListener(runtime.air.update.events.StatusUpdateEvent.UPDATE_STATUS,
                             function(event){statusUpdate(event);}
                             );

    updater.addEventListener(runtime.air.update.events.StatusUpdateErrorEvent.UPDATE_ERROR,
                            function(event){statusUpdateError(event);}
                            );

    updater.addEventListener(runtime.air.update.events.UpdateEvent.DOWNLOAD_START,
                             function(event){downloadStarted(event);}
                             );

    updater.addEventListener(air.ProgressEvent.PROGRESS,
                             function(event){downloadProgress(event);}
                             );
    updater.addEventListener(runtime.air.update.events.UpdateEvent.DOWNLOAD_COMPLETE,
                             function(event){downloadComplete(event);}
                             );

    updater.addEventListener(runtime.air.update.events.DownloadErrorEvent.DOWNLOAD_ERROR,
                             function(event){downloadError(event);}
                             );

        updater.initialize();

    }



    function updaterInitialized(event){

        document.getElementById('isFirstRun').innerHTML =
                                        updater.isFirstRun;

        document.getElementById('previousVersion').innerHTML =
                                        updater.previousVersion;

        document.getElementById('currentVersion').innerHTML =
                                        updater.currentVersion;
        showDiv('Main'),

    }

    function statusUpdate(event){
        event.preventDefault();
        if(event.available){
            showDiv('Available'),
            document.getElementById('version').innerHTML =
                                       event.version;
            document.getElementById('details').innerHTML =
                                       event.details;
        } else {
            showDiv('None'),
        }
     }

    function statusUpdateError(event){
       alert('statusUpdateError'),
    }

    function downloadStarted(event){
       showDiv('Downloading'),
    }

    function downloadError(event){
        showDiv('Main'),
        alert('An error has occurred while downloading the update'),
        window.close();
    }

    function downloadProgress(event){
         document.getElementById('progress').innerHTML =
             Math.ceil((event.bytesLoaded/event.bytesTotal)*100) + "%";
    }

    function downloadComplete(event){
        event.preventDefault();
        showDiv('InstallNow'),
    }

    </script>

    <style>
         div{
             position:absolute;
         }
    </style>

    </head>

    <body onLoad="initialize()">

        <div id="Available" align="center">
        <h3>There is an update available</h3>
        New Version: <span id="version"></span><br/><br/>

        Details:<span id="details"></span><br/><br/>
        <input type="button" onClick="window.close()"
            value="Cancel" />
        <input type="button" onClick="updater.downloadUpdate()"
            value="Download Update" />
        </div>

        <div id="Downloading" align="center">
        <h3>Downloading Update</h3>
        Progress: <span id="progress"></span>
        </div>

        <div id="InstallNow" align="center">
        <h3>Would you like to install the update now?</h3>
        <input type="button" onClick="window.close()"
            value="Cancel" />
        <input type="button" onClick="updater.installUpdate()"
            value="Install Update" />
        </div>

        <div id="Main" align="center">
        <h3>Adobe AIR Update Framework</h3>
        isFirstRun: <span id="isFirstRun"></span><br/><br/>

        previousVersion:<span id="previousVersion"></span><br/><br/>

        currentVersion: <span id="currentVersion"></span><br/><br/>

        <input type="button" onClick="updater.checkNow()"
            value="Check for Updates" />
        </div>

        <div id="None" align="center">
        <h3>You already have the most current version</h3>
        <input type="button" onClick="window.close()"
            value="Cancel" />
        </div>

    </body>
</html>
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset