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.
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.
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.
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-1–Figure 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:
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.
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.
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>
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.
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.
Figure 16-2 shows
the dialog box presented to the user when downloadUpdate
is set to true
in updaterConfig.xml.
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.
You want to use the Adobe AIR Update Framework; however, your client requires specific information to appear in the updater dialog box.
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.
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.
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.
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; }
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).
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);
}
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).
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>
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 div
s 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.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).
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).
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
.
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).
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>