Chapter 16. Deploying Applications

This final chapter in the book discusses the finishing touches that your complete Adobe AIR application might include. To start, the first two sections explain the optional application descriptor file elements. These can be used to provide more information to the end user, customize the application’s installation, or have your application use its own icons.

The third topic in this chapter describes how to provide a seamless installation of your applications. This installation method—where the application will be installed after the user clicks a link on a Web page—can be simpler for the end user, more so than having the user formally download and run the .air file. After that discussion, the chapter provides an example that details three more general techniques that a running application might use. The chapter concludes with a longish but useful example to demonstrate how to make an application update itself.

More Application Descriptor File Options

Chapter 2, “Creating an Application,” walks through the required application descriptor file elements, which are

  • id

  • filename

  • version

  • initialWindow

  • content (within initialWindow)

But the application descriptor file contains many optional elements, all of which I’ll introduce here. The sidebar “Associating File Types” goes into a bit more detail on the optional fileTypes element, and the next section of the chapter explains how to use the icon element. Of course, if you open the descriptor-template.xml file, which is found within the SDK’s templates directory, you’ll see all these elements, along with additional descriptions of them.

To use optional application settings

  • Use the name, description, and copyright elements to personalize your application.

    Although it’s optional, you should almost always provide a name value. It’s displayed by the installer (Figure 16.1) and used to determine where the application should be installed (within the default installation folder). The description value also shows up during the installation process (see Figure 16.1). Including a copyright value, which will appear in an About dialog box on Mac OS X, is a legal protection for you, the developer.

    Some of the information in the application descriptor file, like name and description, appear during the application’s installation.

    Figure 16.1. Some of the information in the application descriptor file, like name and description, appear during the application’s installation.

  • Customize the main application window using the initialWindow element.

    The initialWindow element is required, as is its child element named content. But the initialWindow element can also have these subelements:

    • title

    • systemChrome

    • transparent

    • visible

    • minimizable

    • maximizable

    • resizable

    • width

    • height

    • x

    • y

    • minSize

    • maxSize

    Many of these settings play into the material covered in Chapter 6, “Making Windows,” and they all apply to only the first application window (the primary content window). For example, if you’d like the window to have a set size and location, use the width, height, x, and y values.

    I’ll also add that although the visible element is optional, you’ll want to use it if the user should be able to see your application, because this element’s default value is false.

  • Set an installFolder value to affect where the application will be installed.

    This element allows you to specify a subdirectory within the default installation directory where the application should be installed (Figure 16.2). You might want to do this if the program is part of a suite, so that all the applications are grouped together.

    If the application descriptor file’s installFolder element is used, the Installation Location value will be a subfolder with that name (here, AIR Examples) within the default AIR application folder (/Applications on Mac OS X as shown here).

    Figure 16.2. If the application descriptor file’s installFolder element is used, the Installation Location value will be a subfolder with that name (here, AIR Examples) within the default AIR application folder (/Applications on Mac OS X as shown here).

    Similarly, the programMenuFolder element dictates a subdirectory in which to place the Start/Programs menu shortcut on Windows.

  • Use the customUpdateUI element to create your own update interface.

    If a user installs a newer version of the same application, by default, the AIR application installer will handle that update. If you’d rather have your program manage the update process, set this element’s value to true. Later in this chapter you’ll see an example of how to have an application update itself.

  • Set allowBrowserInvocation if you want this program to be startable through a Web link.

    Using a Shockwave file, a link in a Web page can be used to start a desktop AIR application if this element’s value is set to true.

✓ Tips

  • Your application can access all the application descriptor file’s settings by using this code:

    var data = air.NativeApplication.
    nativeApplication.
    applicationDescriptor;

    After that line, data is a string of text. You’ll then need to turn it into XML using a DOMParser object (see Chapter 14, “Using Other Media”) to access the element values. You can see an example of this in the “Updating an Application” section of this chapter.

  • The publisher ID of the current program is available in air.NativeApplication.nativeApplication.publisherID. This value comes from the digital certificate used to sign the application.

  • The application ID of the current program, which is defined within the application descriptor file, is available in air.NativeApplication.nativeApplication.applicationID.

Using Custom Icons

In the previous section of this chapter, several of the application descriptor file elements are highlighted. Here, I’ll discuss one more element: icon. The icon element contains four subelements, each representing the name of the icon file in a particular size:

<icon>
    <image16x16>icon16.png</image16x16>
    <image32x32>icon32.png</image32x32>
    <image48x48>icon48.png</image48x48>
    <image128x128>icon128.png</image128x128>
</icon>

You can use these elements to identify the icons used to represent your application. If you don’t take this step, the application will use the default Adobe AIR icon (Figure 16.3).

The generic icon used by default for Adobe AIR applications.

Figure 16.3. The generic icon used by default for Adobe AIR applications.

The rules for creating your own application icons are as follows:

  • The icons must be of PNG type.

  • The icons must be included in the built application (i.e., added when you create the .air file).

  • You must provide at least one icon using any of the listed sizes.

As for this last rule, ideally you would provide a version of the icon in each of the sizes. If you don’t, the operating system will scale the closest available icon to the size it needs.

To specify an application’s icon

  1. Create an icon for your application.

    Use any program (I’m pretty sure Adobe has one) to make the image that best represents your application or just looks cool—or, in my case, one that you put together in five minutes because you have limited artistic skills (Figure 16.4).

    My sample application’s visual representation (with acknowledgments to Piet Mondrian).

    Figure 16.4. My sample application’s visual representation (with acknowledgments to Piet Mondrian).

  2. Save the icon in PNG format in four sizes: 128x128, 48, x48, 32x32, and 16x16.

    It’s not required, but you should indicate the size in the filenames—MyApp_16.png, MyApp_32.png, MyApp_48.png, MyApp_128.png—so they’ll be easy to reference in the application descriptor file.

  3. Copy the icons to your project’s directory.

    I recommend putting them within their own icons folder, so they’re kept separate from the rest of the application content.

  4. Edit the project’s application descriptor file so that it uses the icon element (Script 16.1).

    If you placed the icons within an icons folder, the XML to add would be

    <icon>
      <image16x16>icons/MyApp_16.png</image16x16>
      <image32x32>icons/MyApp_32.png</image32x32>
      <image48x48>icons/MyApp_48.png</image48x48>
      <image128x128>icons/MyApp_128.png</image128x128>
    </icon>

    This can go anywhere in the application descriptor file as long as it’s a child of the root element (i.e., not placed within another element like initialWindow).

  5. Be certain to include the icons when you go to build the application.

    How you do this depends on how you build the application. See Chapter 4, “Basic Concepts and Code,” for demonstrations using Aptana Studio, Adobe Dreamweaver, or the command-line adt.

  6. After installing the application, confirm that it uses the custom icon (Figure 16.5).

    The AIR application now uses its own custom icon instead of the default one (Figure 16.3).

    Figure 16.5. The AIR application now uses its own custom icon instead of the default one (Figure 16.3).

✓ Tip

  • As you’ll see later in the chapter, an application’s icon is also used in alert dialogs on Mac OS X.

Example 16.1. By using the icon element within the application descriptor file, an application can use custom icons.

1    <?xml version="1.0" encoding="utf-8" ?>
2    <application xmlns="http://ns.adobe.com/
     air/application/1.0">
3
4       <id>com.dmci.air.Ch16</id>
5       <filename>Update Example</filename>
6       <name>Update Example</name>
7       <version>2.1</version>
8       <description>This is the description
        of this application. It's not very
        descriptive, admittedly.</description>
9       <copyright>2008</copyright>
10
11      <initialWindow>
12         <content>script_16_02.html</content>
13         <visible>true</visible>
14      </initialWindow>
15
16      <installFolder>AIR Examples
        </installFolder>
17      <programMenuFolder>AIR Examples
        </programMenuFolder>
18
19      <icon>
20         <image16x16>icons/MyApp_16.png
           </image16x16>
21         <image32x32>icons/MyApp_32.png
           </image32x32>
22         <image48x48>icons/MyApp_48.png
           </image48x48>
23         <image128x128>icons/MyApp_128.png
           </image128x128>
24      </icon>
25
26   </application>

Seamless Installations

Chapter 1, “Running AIR Applications,” shows how a user can install an AIR application once the user has the .air file. Because installing an application using that file works easily, you can distribute your applications in the same way you might distribute any file, via:

  • CD-ROM

  • Email

  • FTP server

  • Flash drive

You can also make the file available for download from your Web site. However, if that’s how you’re distributing an AIR application, an alternative is to use the seamless installation feature. A seamless installation installs the application on the user’s computer, including the AIR runtime, if necessary, without the user formally downloading and executing the file. In other words, it’s a one-click-while-surfing installation.

Seamless installation uses the badge.swf file that comes with the AIR SDK (in the samples/badge folder). It works with browsers that have Flash Player version 9, update 3, or later installed.

To provide a seamless install

  1. Create, test, debug, and build your AIR application.

    For the sake of these steps, let’s say you end up with a file called MyApp.air.

  2. Create an image for the seamless installer.

    The seamless installer code will create a “badge” containing an image with some text underneath (Figure 16.6). The image should be approximately 215 pixels wide and 100 pixels tall.

    The sample badge that comes with the AIR SDK.

    Figure 16.6. The sample badge that comes with the AIR SDK.

  3. Open a copy of default_badge.html in your text editor or IDE.

    This file, also found within the SDK’s samples/badge folder, contains all the code necessary for placing the seamless install link on an HTML page. Although you’ll eventually want to copy the proper code out of this page and place it within your own site’s context, it’s best to start with this sample file to make sure it all works properly.

  4. Find the call to the AC_FL_RunContent() function:

    AC_FL_RunContent(
    'codebase','http://fpdownload.macromedia.com/pub/shockwave/cabs/flash/swflash.cab',
    'width','217',
    'height','180',
    'id','badge',
    'align','middle',
    'src','badge',
    'quality','high',
    'bgcolor','#FFFFFF',
    'name','badge',
    'allowscriptaccess','all',
    'pluginspage','http://www.macromedia.com/go/getflashplayer',
    'flashvars','appname=My%20Application&appurl=myapp.air&airversion=1.0&imageurl=test.jpg',
    'movie','badge' );

    This function, which is defined within the AC_RunActiveContent.js file that’s included by this page, does all the work. The function call in the HTML page is several lines long, with lots of values being sent to the function.

  5. Within the function call found in step 4, change the value that starts with appname= and ends with test.jpg to match the values for your application.

    This value, which comes after flashvars, is a string of name=value pairs that are used to customize the seamless installation link. To edit this, you’ll want to leave the names, equal signs, and ampersands intact, changing the values that come after each equals sign.

    The appname value should be the colloquial name of the application. Note that this needs to be encoded as it might be in a URL (for example, the name My Application becomes My%20Application). For the appurl value, use an absolute URL to the .air file on your Web site (e.g., http://www.example.com/MyApp.air). The airversion value reflects the minimum version of the Adobe AIR runtime required.

    The imageurl value should be the URL (absolute or relative) for the image file created in step 2. It is optional. Two more optional name=value pairs you can add are buttoncolor and messagecolor. The former is the color of the download button and the latter is the color of the text message displayed if the AIR runtime is not installed. Both take hex values.

    In the end, you might edit this string to read:

    appname=My%20App&appurl=http://www.example.com/MyApp.air&airversion=1.0&imageurl=images/badge.png&buttoncolor=f7f26e&messagecolor=000000

  6. Upload default_badge.html, badge.swf, AC_RunActiveContent.js, the image, and the .air file to your server.

  7. Load the Web page in your browser (Figure 16.7).

    The customized seamless installer badge created for my application.

    Figure 16.7. The customized seamless installer badge created for my application.

  8. Click the Install Now link to confirm that the seamless install will work.

    If the badge is configured properly, the user (which is to say you, for now) should be prompted after clicking that link (Figure 16.8). Clicking the Open option in the prompt will begin the installation process.

    When the user clicks on the badge, the user will be given the choice of opening the file (i.e., installing it immediately), saving it, or canceling the operation.

    Figure 16.8. When the user clicks on the badge, the user will be given the choice of opening the file (i.e., installing it immediately), saving it, or canceling the operation.

  9. If the seamless install works, take the necessary code out of default_badge.html and place it within your own Web page.

✓ Tips

  • You can create your own Shockwave file, replacing badge.swf, to further customize the seamless installation process. This process is covered in the online documentation.

  • To ensure that your server properly delivers manually downloaded AIR files to the end users, tell the Web serving application (Apache, IIS, etc.) to associate the .air extension with application/vnd.adobe.air-application-installer-package+zip. Alternatively, you could zip the .air file so it’s always just downloaded to the user’s computer.

More Application Ideas

In this next example, I’ll discuss three more techniques that applications can incorporate. The first is detecting whether or not the application has been run before. This is useful to know so that the program can do whatever setup is required the first time the program runs. This may include getting information from the user, setting up a database, and so forth.

The second technique is having the program automatically start when the user logs in. To do that, set air.NativeApplication.nativeApplication.startAtLogin equal to true. Prior to taking this step, you should always first confirm that the user wants the application to launch when she or he logs in.

The third technique is detecting whether the user is actively using the computer (i.e., using the keyboard and mouse) or is idle. To do that, add event listeners to the NativeApplication object. You’ll want to listen to USER_IDLE and USER_PRESENT events. A user is considered idle when the mouse or keyboard hasn’t been used for longer than the air.NativeApplication.nativeApplication.idleThreshold value (by default this is five minutes). So, by default, after five minutes of inactivity, a USER_IDLE event is triggered. Whenever the user does use the mouse or keyboard again, the USER_PRESENT event is triggered. You might use this information to tidy up an application’s use of resources when the user goes idle (for example, disconnecting from a database or closing an open file).

To use these new techniques

  1. In your project’s primary HTML file, create a File object (Script 16.2):

    var file = air.File.applicationStorageDirectory.resolvePath('prefs.xml');

    Most applications use a preferences file, which is what this object is a reference to. That file will contain XML data and be stored in the application’s storage directory. Chapter 14 demonstrates this concept in a fully functional example. You’ll also want to copy the prefs.xml file (Script 14.6) into this project’s folder.

  2. Begin an anonymous function to be called after the application has loaded:

    window.onload = function() {
  3. If the preferences file doesn’t exist, copy one from the application directory:

    if (!file.exists) {
      var original = air.File.applicationDirectory.resolvePath('prefs.xml');
      original.copyTo(file);

    If there is no prefs.xml file in the application storage directory, the one that comes with the installed application needs to be copied there, which is what the second and third lines do.

    Most important, for the sake of this example, the conditional is a good and simple test to see if the application is being run for the first time. Unless something went awry, the preferences file will not exist (in the storage directory) only the first time the user runs this program.

  4. If the user wants this application to automatically launch, establish that:

    if (confirm('Always start application when you log in?')) {
      air.NativeApplication.nativeApplication.startAtLogin = true;
    }

    Example 16.2. Three new ideas are demonstrated by this program: checking if it has run before, setting it to automatically open when the user logs in, and watching for user activity and inactivity.

    1    <html><!-- Script 16.2 -->
    2       <head>
    3          <title>Three New Ideas</title>
    4          <script type="text/javascript" src="AIRAliases.js"></script>
    5          <script type="text/javascript">
    6
    7          // Create the object associated with the preferences file:
    8          var file = air.File.applicationStorageDirectory.resolvePath('prefs.xml');
    9
    10         // Function called when the application loads.
    11         window.onload = function() {
    12
    13            // If the preferences file doesn't exist,
    14            // the user hasn't run this program before.
    15            if (!file.exists) {
    16
    17               // Copy the preferences file to its final destination:
    18               var original = air.File.applicationDirectory.resolvePath('prefs.xml');
    19               original.copyTo(file);
    20
    21               // See if the user wants the program to start automatically:
    22               if (confirm('Always start application when you log in?')) {
    23                  air.NativeApplication.nativeApplication.startAtLogin = true;
    24               }
    25
    26            } // End of !file.exists IF.
    27
    28            // Check if this program is automatically launching:
    29            if (air.NativeApplication.nativeApplication.startAtLogin) {
    30               document.getElementById('launch').checked = true;
    31            }
    32
    33         } // End of anonymous function.
    34
    35         // Adjust idle time to 30 seconds:
    36         air.NativeApplication.nativeApplication.idleThreshold = 30;
    37
    38         // Add event listeners:
    39         air.NativeApplication.nativeApplication.addEventListener(air.Event.USER_IDLE, userIdle);
    40         air.NativeApplication.nativeApplication.addEventListener(air.Event.USER_PRESENT, userActive);
    41
    42         // Function called when the user goes idle:
    43         function userIdle(e) {
    44            document.getElementById('idle').checked = true;
    45         }
    46
    47         // Function called when the user returns:
    48         function userActive(e) {
    49            document.getElementById('idle').checked = false;
    50         }
    51
    52         </script>
    53      </head>
    54      <body>
    55      <h3>Some Application</h3>
    56      Automatically Launch: <input type="checkbox" id="launch"><br>
    57      Idle: <input type="checkbox" id="idle">
    58      </body>
    59   </html>

    For simplicity sake, a simple confirmation dialog (Figure 16.9) will ask the user if this program should automatically start when the user logs in. If the user clicks OK, the operating system is notified of this request by assigning the Boolean value true to air.NativeApplication.nativeApplication.startAtLogin.

    This prompt will appear the first time the user runs the application.

    Figure 16.9. This prompt will appear the first time the user runs the application.

  5. Check if the program is set to automatically launch:

    if (air.NativeApplication.nativeApplication.startAtLogin) {
      document.getElementById('launch').checked = true;
    }

    A check box in the application’s window will reflect the user’s decision (Figure 16.10). The first time the user runs this application, if the user clicked OK in the confirmation dialog, this conditional will naturally be true. It will also be true every subsequent time the application is loaded (again, assuming the user clicked OK).

    The simple application with the first check box reflecting the user’s choice in the confirmation dialog (Figure 16.9).

    Figure 16.10. The simple application with the first check box reflecting the user’s choice in the confirmation dialog (Figure 16.9).

  6. Complete the anonymous function:

    } // End of anonymous function.
  7. Set the idle time to a small value:

    air.NativeApplication.nativeApplication.idleThreshold = 30;

    To demonstrate the concept of the user (i.e., you) being idle or active, this value will be set at 30 seconds, so you don’t have to sit around for five minutes to see the results.

  8. Add two event listeners to the native application object:

    air.NativeApplication.nativeApplication.addEventListener (air.Event.USER_IDLE, userIdle);
    air.NativeApplication.nativeApplication.addEventListener (air.Event.USER_PRESENT, userActive);

    The first line specifies that when the user is officially idle, which means that it’s been more than 30 seconds since the user used the mouse or keyboard, the userIdle() function should be called. The second line specifies that when the user is idle and then does something again (uses the mouse or keyboard), the userActive() function should be called.

  9. Define the userIdle() function:

    function userIdle(e) {
      document.getElementById('idle').checked = true;
    }

    This function checks a box in the application window when the user goes idle (Figure 16.11).

    After 30 seconds of inactivity, the second check box will automatically be checked by the application.

    Figure 16.11. After 30 seconds of inactivity, the second check box will automatically be checked by the application.

  10. Define the userActive() function:

    function userActive(e) {
       document.getElementById('idle').checked = false;
    }

    This function unchecks the box that indicates the user is idle.

  11. Within the body of the page, create the two requisite check boxes:

    Automatically Launch: <input type="checkbox" id="launch"><br>
    Idle: <input type="checkbox" id="idle">

    In a more complete application, when the user unchecked the Automatically Launch check box, a function would be called that assigned a value of false to air.NativeApplication.nativeApplication.startAtLogin.

  12. Save, test, debug, and run the completed application.

    To fully test this, you should build and actually install the program; don’t just use the Adobe Debug Launcher (adl). Make sure that you also include a prefs.xml file in the packaged application.

    The first time you run this program, the preferences file will be moved to the application’s storage directory and you’ll see the confirmation dialog. Click OK, and then log out and log back in. The application should automatically launch, and the check box should reflect your choice.

    To test the idle/active check box, don’t do anything for 30 seconds. It doesn’t matter if this application is currently active or not, it will still watch for the idle and present events.

✓ Tips

  • To stop this application from automatically opening every time you log into your computer, you’ll need to have it set air.NativeApplication.nativeApplication.startAtLogin to false, and then rerun the application. Alternatively, you can search online for operating system-specific instructions for removing a program from the automatically start list.

  • You can see how long it has been since the last time the user did something by referring to air.NativeApplication.nativeApplication.timeSinceLast-UserInput.

  • To react to the user making the application active (i.e., turning back to it after using other applications), watch for an ACTIVATE event:

    air.NativeApplication.nativeApplication.addEventListener( air.Event.ACTIVATE, nowActive);

Updating an Application

One way to update an application is to have the user download and install the latest version of it. When a user installs the new version with the same application ID but a later version number (both from the application descriptor file) of an AIR application they have already installed, the user will be prompted to update it (Figure 16.12).

The AIR installer will ask the user whether to replace the current version of an application with a newer version.

Figure 16.12. The AIR installer will ask the user whether to replace the current version of an application with a newer version.

Another option is to have an application check for and handle updates itself. To do so, the application needs to check for the existence of a more current version. This means that the application first needs to know its own version number, which is defined in the application descriptor file. You can get that data by referring to air.NativeApplication.nativeApplication.applicationDescriptor. The returned string then needs to be turned into XML and parsed to get the version information (this next script will demonstrate all that).

The next step is for the application to communicate with your server to see if a newer version is available. The easiest way to accomplish that is to create a plain text page on your server that stores the current application version. Then the application could perform an XMLHttpRequest to that page to retrieve the value. Or the application could use a URLLoader object to read in the information (see Chapter 13, “Networking”).

If a new version is available, the application should download it. That will require creating a URLRequest object referring to the new version on the server and loading the new version into a URLStream. Then that data will be written to a new file on the user’s computer.

After all that has been accomplished, the updating process starts with an Updater object:

var updater = new air.Updater();

You’ll also need a reference to the downloaded file (the latest version of the application):

var file = air.File.desktopDirectory.resolvePath('MyApp.air');

Finally, call the update() method of the Updater() object. It takes the file object as the first argument and the new version number as the second:

updater.update(file, version);

As soon as the update() method is called, the current invocation of the application will terminate, the new version will be installed, and then the new version will be opened. It’s all very professional, and this next script will demonstrate all the necessary code. As you can already tell, there are many steps to this process and the application I’ve created uses seven user-defined functions. But it’s still all accomplished within a little more than 50 lines of code (not including comments and blank lines).

To use the Updater class

  1. In your project’s primary HTML file, declare the necessary global variables (Script 16.3):

    var thisVersion, currentVersion, xhr, newAppFile, data, urlStream = null;

    Example 16.3. This script has all the code required for an application to update itself.

    1    <html><!-- Script 16.3 -->
    2       <head>
    3          <title>Update Example</title>
    4          <script type="text/javascript" src="AIRAliases.js"></script>
    5          <script type="text/javascript">
    6
    7          // Declare the global variables:
    8          var thisVersion, currentVersion, xhr, newAppFile, data, urlStream = null;
    9
    10         // Function called when the application loads.
    11         // This function begin the updating process.
    12         // It gets the two application versions.
    13         window.onload = function() {
    14
    15            // Get the version of the running application:
    16            getThisVersion();
    17
    18            // Get the most current version:
    19            getCurrentVersion();
    20
    21         } // End of anonymous function.
    22
    23         // Function gets the version of the running
    24         // application from the application descriptor file.
    25         function getThisVersion() {
    26
    27            // Get the data:
    28            var appData = air.NativeApplication.nativeApplication.applicationDescriptor;
    29
    30            // Turn the file data into an XML object:
    31            var dp = new DOMParser();
    32            var xml = dp.parseFromString(appData, 'text/xml');
    33
    34            // Parse out and return the version value:
    35            var version = xml.getElementsByTagName('version')[0].firstChild;
    36            thisVersion = version.nodeValue;
    37
    38         } // End of getThisVersion() function.
    39
    40         // This function performs an XMLHttpRequest to get the
    41         // version number of the most recent release.
    42         function getCurrentVersion() {
    43
    44            // Perform the request:
    45            xhr = new XMLHttpRequest();
    46            xhr.open('get', 'http://www.example.com/air/version.txt');
    47            xhr.onreadystatechange = askAboutUpdate;
    48            xhr.send(null);
    49
    50         } // End of getCurrentVersion() function.
    51
    52         // This function asks the user if they want to update
    53         // the application, if appropriate.
    54         function askAboutUpdate() {
    55
    56            // Check the readyState value:
    57            if (xhr.readyState == 4) {
    58
    59                // Get the current version:
    60                currentVersion = xhr.responseText;
    61
    62                // If the current version is greater, ask the user:
    63                if (currentVersion > thisVersion) {
    64                   if (confirm('Update to the newest version?')) {
    65                      downloadNewVersion();
    66                   }
    67                } else {
    68                   alert('The current version is up to date.');
    69                }
    70
    71             } // End of readyState IF.
    72
    73          } // End of askAboutUpdate() function.
    74
    75          // This function downloads the latest version.
    76          function downloadNewVersion() {
    77
    78             // Create the variables:
    79             var addr = 'http://www.example.com/air/MyApp.air';
    80             var url = new air.URLRequest(addr);
    81             urlStream = new air.URLStream();
    82             data = new air.ByteArray();
    83
    84             // Add an event listener:
    85             urlStream.addEventListener(air.Event.COMPLETE, saveNewVersion);
    86
    87             // Get the data:
    88             urlStream.load(url);
    89
    90          } // End of downloadNewVersion() function.
    91
    92          // Function that writes the downloaded data to a file:
    93          function saveNewVersion(e) {
    94
    95             // Read the downloaded data into the 'data' variable:
    96             urlStream.readBytes(data, 0, urlStream.bytesAvailable);
    97
    98             // Write the data to a file:
    99             newAppFile = air.File.desktopDirectory.resolvePath('MyApp.air');
    100            var fileStream = new air.FileStream();
    101            fileStream.open(newAppFile, air.FileMode.WRITE);
    102            fileStream.writeBytes(data, 0, data.length);
    103            fileStream.close();
    104
    105            // Call the function that performs the update:
    106            updateApplication();
    107
    108         } // End of saveNewVersion() function.
    109
    110         // This function performs the actual update.
    111         function updateApplication() {
    112
    113            var updater = new air.Updater();
    114            updater.update(newAppFile, currentVersion);
    115
    116         } // End of updateApplication() function.
    117
    118         </script>
    119      </head>
    120      <body>
    121         <h3>Update Example</h3>
    122      </body>
    123   </html>

    Because this script uses so many functions, a number of global variables are required (because each of these will be referred to in more than one function). They are each initially given a null value.

  2. In an anonymous onload function, get the ball rolling:

    window.onload = function() {
      getThisVersion();
      getCurrentVersion();
    }

    As I said, there are seven functions involved (a figure later in the chapter will show the logic), beginning with this one. The premise is that after the application has loaded, a check would be made to see if a newer version of the application is available. To do that, calls to the getThisVersion() and getCurrentVersion() functions are made.

  3. Begin the getThisVersion() function:

    function getThisVersion() {
      var appData= air.
    NativeApplication.nativeApplication.applicationDescriptor;
      var dp = new DOMParser();
      var xml = dp.parseFromString (appData, 'text/xml');

    Very similar to code found in Chapter 14, this function starts by reading the contents of the application descriptor file into the appData variable. You can do this by simply referring to air.NativeApplication.nativeApplication.applicationDescriptor.

    Then a new object of type DOMParser is created, and the appData string is turned into an XML object.

  4. Complete the getThisVersion() function:

      var version = xml.getElementsByTag Name('version')[0].firstChild;
      thisVersion = version.nodeValue;
    } // End of getThisVersion() function.

    This cumbersome code is best explained in Chapter 14. In short, the first line returns the first item from the XML data whose element name is version. There will only be one such element, but getElementsByTagName() always returns an array. The firstChild attribute of that element is the value of the element, which will be a text node. Finally, the value of that text node, which is the value of the element—e.g., 1.2 or 3.59—will be assigned to the global thisVersion variable.

  5. Define the getCurrentVersion() function:

    function getCurrentVersion() {
      xhr = new XMLHttpRequest();
      xhr.open('get', 'http://www.example.com/air/version.txt');
      xhr.onreadystatechange = askAboutUpdate;
      xhr.send(null);
    } // End of getCurrentVersion() function.

    This function finds out what the most recent version of the application is. That value will be stored in a text file on a server (presumably the same Web site where the user downloaded the program in the first place). This code performs a basic XMLHttpRequest for that document. The askAboutUpdate() function will be called when the request’s readyState value changes.

  6. Begin defining the askAboutUpdate() function:

    function askAboutUpdate() {
      if (xhr.readyState == 4) {
         currentVersion = xhr.responseText;

    This function is called as the XMLHttpRequest object’s readyState value changes. Once that value equals 4, the request is complete and the response (which is the entire contents of the version.txt) file will be assigned to the global currentVersion variable. This code as written will only work if the text file contains just a number and absolutely nothing else.

  7. If there’s a newer version of the application available, ask the user whether to install it:

    if (currentVersion > thisVersion) {
      if (confirm('Update to the newest version?')) {
        downloadNewVersion();
      }
    } else {
      alert('The current version is up to date.');
    }

    At this point in the script, the two numbers are stored in variables. One reflects the most recent version of the application available (fetched from the Web), and the other reflects the version of the currently running application. If the former is greater than the latter, a new version is available and the user can be asked whether to update the application (Figure 16.13).

    If a new version of the application is available, the user is asked whether to perform an update.

    Figure 16.13. If a new version of the application is available, the user is asked whether to perform an update.

    Otherwise, the user is notified that the version running is the most current one available (Figure 16.14). You may not want to do this in a real application, but here it confirms that the process works.

    If no new version of the application is available, a simple statement says as much.

    Figure 16.14. If no new version of the application is available, a simple statement says as much.

  8. Complete the askAboutUpdate() function:

      } // End of readyState IF.
    } // End of askAboutUpdate() function.
  9. Begin defining the downloadNewVersion() function:

    function downloadNewVersion() {
      var addr = 'http://www.example.com/air/MyApp.air';
      var url = new air.URLRequest(addr);
      urlStream = new air.URLStream();
      data = new air.ByteArray();

    If the user clicks OK in the confirmation dialog (Figure 16.13), this function will be called. It downloads the newest version of the application from the server. To do that, it first identifies the full URL of the file to be downloaded. Then it creates three new objects: one URLRequest, one URLStream, and one ByteArray. The first two are discussed in Chapter 13 and the third is introduced in Chapter 10, “Working with File Content.”

  10. Complete the downloadNewVersion() function:

      urlStream.addEventListener(air.Event.COMPLETE, saveNewVersion);
      urlStream.load(url);
    } // End of downloadNewVersion() function.

    To perform the download, there are two final steps. First, an event listener is added to the URLStream object, stating that the saveNewVersion() function should be called when the entire file has been downloaded. Second, the file is loaded into the stream.

  11. Begin defining the saveNewVersion() function:

    function saveNewVersion(e) {
      urlStream.readBytes(data, 0, urlStream.bytesAvailable);

    This function will take the data read from the server and store it as a file on the computer (so that it can be used for the update). To start, it takes the data loaded into the URLStream and writes it into the data global variable.

  12. Write the data to a file:

    newAppFile = air.File.desktopDirectory.resolvePath('MyApp.air');
    var fileStream = new air.FileStream();
    fileStream.open(newAppFile, air.FileMode.WRITE);
    fileStream.writeBytes(data, 0, data.length);
    fileStream.close();

    The global newAppFile variable will be a File object that points to the new version of the application. By default, this will be on the user’s desktop and be given a name of MyApp.air. A FileStream object is created, the file is opened for writing, all the data is written to the file, and the file stream is closed.

  13. Complete the saveNewVersion() function:

      updateApplication();
    } // End of saveNewVersion() function.

    Now that the newest version of the application is on the user’s computer, the last step is to actually perform the update. That will take place in the updateApplication() function, called here after the file has been saved. Figure 16.15 shows the complete logic flow of this application.

    The long, but actually straightforward, logic of this application.

    Figure 16.15. The long, but actually straightforward, logic of this application.

  14. Define the updateApplication() function:

    function updateApplication() {
      var updater = new air.Updater();
      updater.update(newAppFile, currentVersion);
    }

    Ironically, the function that does the most important part is the easiest to write. An object of type Updater is created, and then its update() method is called. Its first argument is the file that represents the new version of the application. Its second argument is the version number.

  15. Create a file called version.txt that stores just a version number and place it on your server.

    The version number needs to be a simple integer or real number: 1 or 2.3 or 6.34. It cannot be v1 or 2.3.45. The number cannot be followed by any spaces, newlines, or carriage returns.

  16. Go back to the code explained in step 5 and change the URL to match your server, if they don’t match already.

    This whole application will not work unless the two URLs used by it are accurate.

  17. Make sure the version of this application, as defined in the application descriptor file, matches the version number you put in version.txt.

    The update() method takes two arguments: the file to be used for the update and the version number. If the file (i.e., the new version of the application) does not use the same version number as that in the text file (and therefore, as that used in the update() method), the update won’t proceed.

  18. Save and build the completed application.

    This first build will represent the “newer” version of the application.

  19. Place the finished .air file on your server.

    Make sure that it has a name and location that matches the URL used in step 9.

  20. Change the version of the application, as defined in the application descriptor file, to be lower than that used in the already built version.

    This next build will represent the “older” version of the application. So if you built the previous version of this application as version 2.3, this version needs to be 1.0 or 1.8, or 2.23—anything less than 2.3.

  21. Save, build, install, and run the completed application.

    It’s very important that you actually install and run the application. You cannot test all of this using the command-line adl.

    When you run the program, you should see a prompt like that in Figure 16.13. Click OK: The file will be downloaded, the application will close, be updated, and restart, generating the alert in Figure 16.14. Depending on the speed of your Internet connection and your computer, all of this should happen rather quickly (because the application file is really small).

✓ Tips

  • As an alternative, the version.txt file on the server could be called version.xml, storing more information:

    <?xml version="1.0" encoding="UTF-8"?>
    <update>
      <majorVersion>2</majorVersion>
      <minorVersion>3</minorVersion>
      <minFreeUpgradeVersion>2.0</minFreeUpgradeVersion>
    </update>

    Then the XMLHttpRequest would refer to the responseXML instead of responseText.

  • Keep in mind that every AIR application is associated with a certificate, and self-signed certificates are only valid for five years. This means you can only provide updates for a self-signed application for five years. After that you’ll need to create a new application (with a new application ID) associated with a new certificate. This is another reason why professional applications require legitimate signing certificates.

..................Content has been hidden....................

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