How to update Adobe AIR applications automatically with JavaScript - AIRUpdater.js

Published on Monday, June 9th, 2008

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.js file 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!

19 comments

  • Remy Sharp
    June 9th, 2008 at 23:39

    Good man! Thanks for making it public. Now to crack on with my little AIR app.

  • Douglas Karr
    June 10th, 2008 at 3:28

    Very cool, have you given thought to using JQuery?

  • Robert Nyman - author
    June 10th, 2008 at 12:48

    Remy,

    Well, I got a bit worried that you’d put something out first, so I had to beat you to it. :-)

    Douglas,

    Thanks! This code was meant to be completely JavaScript-library independent. In my AIR applications I use the faster and more light-weight DOMAssistant; an example can be seen in the updater for facedesk.

  • Thoughts on developing with the Adobe AIR framework - Robert’s talk - Web development and Internet trends
    June 10th, 2008 at 19:52

    [...] updates to the end users isn’t as easy as it seems nor as it should be. I’ve created a script to automatically update AIR applications, inspired by others, but it was far too much [...]

  • Kevin Dangoor
    June 13th, 2008 at 13:16

    Hi Robert,

    This is a handy looking piece of code! I don’t see a license applied to it. Is this usable under some open source license?

    Thanks!
    Kevin

  • Robert Nyman - author
    June 13th, 2008 at 19:42

    Kevin,

    Thank you! It’s my bad, I didn’t put in the source file…

    It is released as open source, under a MIT license (this is mentioned and there’s a link to the terms for that license at the AIRUpdater project start page).

  • johnbillion
    July 20th, 2008 at 2:15

    If your application has problems downloading the .air installer file from your server, you may need to explicitly set the mime type on your server so it handles the file correctly.

    Check out http://www.rogue-development.com/blog2/2007/10/air-mime-type/ for details.

    I had to do this as my server was trying to preprocess the .air file before sending it, instead of just sending it as an application file.

  • Mark
    July 31st, 2008 at 21:32

    Thank you so much for this!

    I’m going to be integrating it into my AIR application that’s still in development.

  • Robert Nyman - author
    August 18th, 2008 at 22:51

    johnbillion,

    Thanks for the tip!

    Mark,

    You’re welcome!

  • seme
    September 8th, 2008 at 12:24

    What about updating the database ? If changes were made to the SQLite database in the new version, is there a smooth and easy way to detect the changes (fields/tables added/removed) and apply it to the old database ?

  • seme
    September 9th, 2008 at 0:41

    Is there a way to have a series of commands executed right after the update is completed only once ?

    The idea here is to update the old database with new fields based on the old version number.

  • Robert Nyman - author
    September 9th, 2008 at 12:34

    seme,

    Interesting questions. But no, this only checks version number of the application. If you want to make extra calls when it is done, you need to tweak the script.

  • Hemagiri
    October 11th, 2008 at 11:49

    We need to develop one sales presentation in flash with Adobe AIR capabilities. The idea is once developed and deployed, sales guys will get updated content using Adobe AIR Update Frame work. As the intial application will be around 10 MB and it will have many seperate SWFs. We intend to update only few swf or few XML files in further release of applicaiton. Otherwise updating entire APP will be of Huge size. Does AIR have this kind of support / capabilities.

  • Robert Nyman - author
    October 11th, 2008 at 20:14

    Hemagiri,

    As far as I know, it’s not possible.

  • HB
    October 24th, 2008 at 8:35

    Even though you can’t update only parts of an AIR app using the AIR Updater framework, you could certainly incorporate your own code to download and overwrite specific XML/swf files. So your sales guys wouldn’t know the difference, and (perhaps even better, depending on your viewpoint) the app wouldn’t have to restart after downloading the new content.

    The code to download would be very similar to initUpdateApplication above, and when it’s done the app could display its own message if you want, or it could just start using the updated files seamlessly.

    At work we have a digital sign app which gets new XML playlists and data feeds, FLV / SWF video ads and static image ads, and they automatically update those assets without AIR’s update framework, and when the app itself needs a fix, it uses the update framework.

  • Robert Nyman - author
    October 26th, 2008 at 22:31

    HB,

    Absolutely, that could be an interesting option!

  • Auto Update Air Applications | Adobe AIR Tutorials
    October 30th, 2008 at 12:28

    [...] Learn more on how to push application updates to the end users @  AIRUpdater [...]

  • Shannon
    November 2nd, 2008 at 4:05

    I feel like a complete idiot asking this because it should be such a simple question….

    but I’ve been trying to figure it out all day.

    How do I provide an ok/cancel (or yes/no) confirmation window within the application when it loads to state there’s an update available and give the user the option to upgrade now?

    I see the “release-notes” and “update-application” in the js above, but everything I’ve tried on my application didn’t seem to do anything.

    I have the above code in a js file and imported in the header.

    Many thanks,
    Shannon

  • Robert Nyman - author
    November 2nd, 2008 at 9:23

    Shannon,

    There’s also an element named cancel-update expected, if you look closer in the compareVersions method. Just make sure to have an element named that, and a click on it will hide the update dialog.

Share your thoughts:

HTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> . If you want to display code examples, please remember to write &lt; for < and &gt; for >.

Comment preview

Top results