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.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!
Good man! Thanks for making it public. Now to crack on with my little AIR app.
Very cool, have you given thought to using JQuery?
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.
[…] 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 […]
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
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).
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 <a href="http://www.rogue-development.com/blog2/2007/10/air-mime-type/” target=”_blank”>www.rogue-development.com/blog2/2007/10/air-mime-… 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.
Thank you so much for this!
I'm going to be integrating it into my AIR application that's still in development.
johnbillion,
Thanks for the tip!
Mark,
You're welcome!
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 ?
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.
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.
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.
Hemagiri,
As far as I know, it's not possible.
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.
HB,
Absolutely, that could be an interesting option!
[…] Learn more on how to push application updates to the end users @ΓΒ AIRUpdater […]
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
Shannon,
There's also an element named cancel-update expected, if you look closer in the <code>compareVersions</code> method. Just make sure to have an element named that, and a click on it will hide the update dialog.
Great script. I knew nothing, now I know a bit more π
Anyone seen a packaged script like this that handles docking and undocking an air application to the system tray. I can’t seem to find anything that doesn’t rely on Flash, Flex or AS3.
Sorry because I try to fix my comment format but it’s not ok. You can read my full question in http://www.actionscript.org/forums/showthread.php3?t=192460
Hi Robert Nyman! I have problem with javascript. Can you help me? I try to use Javascript inside Actionscript which call MS word to read document. But it error when I initial ActiveXObject.
Here is my code
test.mxml
<code>
</code>
htmlwithJS.html
<code>
function loadworddoc(){
var doc = new ActiveXObject("Word.Application");
doc.Visible=false;
doc.Documents.Open("C:SamSam.doc");
var txt;
txt = doc.Documents("C:SamSam.doc").Content;
document.all.myarea.value = txt;
doc.quit(0);
}
test now
</code>
If I run AIR app the error message is : ReferenceError: Can't find variable: ActiveXObject but if I run each htmlwithJS.html I can see it load MS Word document. Why it is wrong?
Thank any suggest!!!
Hai Anh
Hi Robert Nyman! I have problem with javascript. Can you help me? I try to use Javascript inside Actionscript which call MS word to read document. But it error when I initial ActiveXObject.
Here is my code
test.mxml
<code>
</code>
htmlwithJS.html
<code>
function loadworddoc(){
var doc = new ActiveXObject("Word.Application");
doc.Visible=false;
doc.Documents.Open("C:SamSam.doc");
var txt;
txt = doc.Documents("C:SamSam.doc").Content;
document.all.myarea.value = txt;
doc.quit(0);
}
test now
</code>
If I run AIR app the error message is : ReferenceError: Can't find variable: ActiveXObject but if I run each htmlwithJS.html I can see it load MS Word document. Why it is wrong?
Thank any suggest!!!
Hai Anh
enlightened,
Sorry, no ideas there.
hai anh,
Sorry, I have no idea how to solve that.
[…] AIRUpdater […]
[…] How to update Adobe AIR applications automatically with JavaScript – AIRUpdater.js – robertnyman.com […]
Have you given thought to reworking this code to take advatage of the new built in updater class?
Andy,
No, not at the moment, but if you want to give it a go, feel free! π
Awesome, thanks for sharing! Has anyone seen anything for auto-PACKAGING AJAX AIR apps on a server? I'm thinking about being able to dynamically build an AIR installer on a Linux server based on simple choices in a PHP-based UI… searching for possible deployment solutions.
hi to all
well ive recently finished an app which i made in flash cs4 and converted to an air app….the issue iam having is the update code….iam wanting to create a seamless install and have the air app update the users app when i update mine on my server..ive tried so many options and tried to find info,i think i nearly nailed it,but the update method doesnt seem to work i get an error Error #2044: Unhandled IOErrorEvent:. text=Error #2032: Stream Error.
at VisNova_fla::MainTimeline/frame1()[VisNova_fla.MainTimeline::frame1:66]
also this error Error: This method is not supported if application is launched from ADL.
at flash.desktop::Updater/update()
this is my code
import flash.desktop.*;
import flash.filesystem.*;
import flash.net.*;
var updater:Updater = new Updater();
var airFile:File = File.desktopDirectory.resolvePath("VisNova.air");
var version:String = "2.01";
updater.update(airFile, version);
var urlString:String = "http://visnova.biz/AIR/vis/VisNova.air";
var urlReq:URLRequest = new URLRequest(urlString);
var urlStream:URLStream = new URLStream();
var fileData:ByteArray = new ByteArray();
urlStream.addEventListener(Event.COMPLETE, loaded);
urlStream.load(urlReq);
function loaded(event:Event):void {
urlStream.readBytes(fileData, 0, urlStream.bytesAvailable);
writeAirFile();
}
function writeAirFile():void {
var file:File = File.applicationStorageDirectory.resolvePath("My App VisNova.air");
var fileStream:FileStream = new FileStream();
fileStream.open(file, FileMode.WRITE);
fileStream.writeBytes(fileData, 0, fileData.length);
fileStream.close();
}
iam not very experienced with as3 and this is my first air app,but its for my users that buy my products,so its very important to me….if someone is willing to help,i will pay for there services…you can contact me at shayne@visnova.biz
thanks….Shayne Shiells
Greg,
Thank you!
shayne shiells,
I'm sorry, I don't have any experience with how to do that with Flash in Adobe AIR. Good luck!
Thanks for this mate – just what I needed π
brothercake,
Sweet! It's an honor to help someone like you!
Just what I needed to polish off an app that I'm creating. Well commented so I could easily modify it to suit my requirements. Thanks for sharing.
Brilliant script! I can't tell you how grateful I am, this has just saved me countless hours. Thank you!!
Hi Mate,
I dont know if this is just me being stupid, but I cannot get this to work
I have a microsite which im distributing via USB sticks as an air app. I have set the version in the application.xml file to 1.0 and packaged the app and installed it
I have then created a version called with 1.1 in the application.xml file, saved it as abstracts-1.1.air and uploaded it to the location that i pointed to in the AIRUpdater JS file. I haev also included a versioning.xml file with the correct information in it also.
However, no matter what i do I dont get a dialogue saying update available.
Anything ive missed?
Thanks
Dan
Dan,
Sounds ok at least. Sorry I can't help more, was quite some time since I worked with it.
[…] across very interesting article by @robertnyman and one by David Tucker Bookmark on DeliciousDigg this postRecommend on […]
Found this at cookbooks.adobe.com:
Updating an AIR application with the Update Framework – AIR 1.1
… and this one at help.adobe.com:
Updating AIR applications
Hello, Awesome script, thanks for posting it, I realize its pretty old but it helped out a ton. Question… After making the air file, note I don’t have a certificate but am just developing it and testing my app right now. I get an error after the update saying installer is misconfigured.
Any thoughts on this?
josh,
Sorry, no idea. Haven’t worked with it in years.
Thanks Robert, it’s very2 simple.
First of all thanks for the code. But i’m keep on trying to update my application it says “This application cannot be installed because this installer has been mis-configured. Please contact the application author for assistance.”
How to fix this?
I have tried with change the certificate (created 2 certificates for each air package).
Version is 0.9 to 1.0
I’m using air 2.0
Application working fine. Only updater is the issue.
What is the solution here plz?
Even if i try to install the package manually it asks for replace the version. But while auto update it says misconfigured. What shall i do
Manoj,
Sorry, the code here is 4 and a half years old, and it’s very likely that Adobe have changed things since.
I’d recommend talking to them. Good luck!