How to update Adobe AIR applications automatically with JavaScript - AIRUpdater.js
When developing applications with Adobe AIR, a vital feature is being able to push application updates to the end users. As it’s quite hard to find complete examples from Adobe, I thought I’d offer you a script how to do it.
Background
Going through the Adobe documentation for HTML and AJAX development, which overall is quite sparse, the information for updating applications isn’t complete for most peoples’ needs, and it doesn’t offer any example of version comparison to see if an update is needed or not.
I was attending the on AIR Tour event in Stockholm last Monday, which by the way was a great event with good presentations and lots of gifts, candy, assorted food for us spoiled web developers. It was good to meet Mike Chambers in person and ask about “cache object is too large to persist to store” errors when developing with Adobe AIR on Macs (this was then solved with the latest Apple OS X upgrade), and to have the possibility to ask Mike and Kevin Hoyt about some of my Adobe AIR ideas and if they were actually possible to realize.
One presentation went through updating applications which was exactly what basically everyone needs. It was written in ActionScript, but unfortunately I couldn’t find any occurrence of it online. After a long time searching, I found another gem: David Tucker’s AIR API - Performing Updates in JavaScript. He has some sample code and an AIR project you can download and play around with.
I wanted to package it even more, and basically make it as easy as possible to adapt to any application. Therefore I created AIRUpdater. What you need to do to use it is:
- Include it on your AIR application page:
<script type="text/javascript" src="js/AIRUpdater.js"></script> - Customize URLs in the
AIRUpdater.jsfile for which URL to use to compare versions, and which to get a new release from. - Adapt the presentation of an update dialog to your end users for the best possible experience.
That’s it!
The code
The code is heavily commented in respect to the parts you can, and should, customize. The general idea is to use your URLs and have one that offers an XML file you can use to do version checking against, and another where you can download the actual update (i.e. the .air file).
This script, in its original form, takes for granted that you use numbers for versioning, since it’s the simplest and most fool-proof approach. Naturally, you can change thus if you want to.
From here, you can download the AIRUpdater code right away, or start by going through the complete code below.
/*
Written by Robert Nyman, http://www.robertnyman.com
Inspired by http://www.insideria.com/2008/03/air-API-performing-updates-in-1.html, and then modified
*/
var AIRUpdater = function () {
// This is only used for the filename of the installer
var applicationName = "MyApp.air";
var applicationVersion = 0;
var latestVersion = 0;
/*
URL to go to to check the value of the <version> and <releasenotes>
The value in version is compared to the one in the applications XML setup file,
and an update dialog is triggered if the <version> in the below XML file is higher
From there on, suggested alternatives for the end user is to
start an update or cancel it for the moment
Suggested XML structure:
<?xml version="1.0" encoding="UTF-8"?>
<application>
<latestversion>0.7</latestversion>
<releasenotes>Added automatic update downloading feature.</releasenotes>
</application>
*/
var latestVersionCheckUrl = "http://www.myapp.com/versioning.xml";
var updateAvailable = null;
var updateAvailableDialog = null;
var releaseNotes = null;
var releaseNotesText = "";
/*
Change this URL to the download URL of your AIR app. Version number
and ".air" extension will automatically be added; version taken
from the XML value found in the latestVersionCheckUrl page
*/
var updaterUrl = "http://myapp.googlecode.com/files/myapp-";
var stream = null;
var updateFile = null;
var getApplicationVersion = function () {
// This will get the version of the currently installed application
var appXML = air.NativeApplication.nativeApplication.applicationDescriptor;
var xmlObject = new DOMParser().parseFromString(appXML, "text/xml");
applicationVersion = parseFloat(xmlObject.getElementsByTagName('version')[0].firstChild.nodeValue);
};
var getLatestVersion = function () {
/*
Checks for what the latest available version is
from the URL specified in latestVersionCheckUrl
*/
var XMLHttp = new XMLHttpRequest();
XMLHttp.onreadystatechange = function () {
if (XMLHttp.readyState === 4) {
var response = XMLHttp.responseXML;
var releaseNotesNode = response.getElementsByTagName("releasenotes")[0];
/*
Adds a reference to a releaseNote for the latest version,
IF a <releasenotes> node exists
*/
if (typeof releaseNotesNode === "object" && releaseNotesNode.firstChild) {
releaseNotesText = releaseNotesNode.firstChild.nodeValue;
}
var latestVersionNode = response.getElementsByTagName("latestversion")[0];
/*
Triggers a version comparison with the existing installed application,
IF a <latestversion> node exists
*/
if (typeof latestVersionNode === "object" && latestVersionNode.firstChild) {
latestVersion = parseFloat(latestVersionNode.firstChild.nodeValue, 10);
compareVersions();
}
}
};
XMLHttp.open("GET", latestVersionCheckUrl, true);
XMLHttp.send(null);
};
var compareVersions = function () {
if (applicationVersion > 0 && latestVersion > 0 && latestVersion > applicationVersion) {
/*
Here you should, for example, present an "Update available" to your
end user, and give them the option to start the update
The code below is just sample code:
*/
// Present release notes for the new version available
document.getElementById("release-notes").innerHTML = releaseNotesText;
// Add onclick event to start update button
document.getElementById("update-application").onclick = initUpdateApplication;
// Add onclick event to cancel update button
document.getElementById("cancel-update").onclick = function () {
document.getElementById("update-available-dialog").style.display = "none";
};
// Show the update dialog to the end user
document.getElementById("update-available-dialog").style.display = "block";
}
};
var initUpdateApplication = function () {
/*
The updating has started. Prefereably, you'd like to hide
or disable the start and cancel update buttons now
*/
stream = new air.URLStream();
/*
This event is recommend to give the end user continuous
feedback about how the update goes
*/
stream.addEventListener(air.ProgressEvent.PROGRESS, updatingStatus);
stream.addEventListener(air.Event.COMPLETE, updateApplication);
// Note that the latest version number and ".air" extension is automatically added
stream.load( new air.URLRequest(updaterUrl + latestVersion + ".air"));
};
var updatingStatus = function (e) {
// This is example code to show updating status
var percentage = Math.round((e.bytesLoaded / e.bytesTotal) * 100);
document.getElementById("current-updating-status").innerHTML = percentage + "%";
};
updateApplication = function () {
var ba = new air.ByteArray();
stream.readBytes(ba, 0, stream.bytesAvailable);
updateFile = air.File.applicationStorageDirectory.resolvePath(applicationName);
fileStream = new air.FileStream();
fileStream.addEventListener( air.Event.CLOSE, installUpdate );
fileStream.openAsync(updateFile, air.FileMode.WRITE);
fileStream.writeBytes(ba, 0, ba.length);
fileStream.close();
};
var installUpdate = function () {
var updater = new air.Updater();
// Notice that the version name has to be present as a second parameter
updater.update(updateFile, latestVersion.toString());
};
return {
init : function () {
getApplicationVersion();
getLatestVersion();
}
};
}();
window.onload = AIRUpdater.init;
Happy updating!
I hope this script helps you as much as it has helped me, since it’s now seamless to start developing new applications and already have this important functionality on place.
Happy Adobe AIR developing!


