Auto-Updating Extensions

Eric Hamiter’s tutorial on how to enable extension updates is pretty handy. As he points out, in order to make it so that the “Update” button in the extensions manager actually does something for your extension, you simply provide a value for the updateURL paramater within your extension’s install.rdf and make sure there’s a valid RDF file being served up from that URL. This file contains information about the current version and from where the latest xpi file can be downloaded. When you highlight an extension in the extensions manager and click the update button, it checks the current version number against what’s listed in your remote RDF, and if yours is old, it pops up the update wizard that walks you through doing an update. Very nifty.

But let’s say I want to force an update (or at least prompt the user to let him or her know that a new version exists. Supposedly, there are some configuration options you can set to cause extensions (and Firefox itself) to automatically update (thanks to Nigel McFarlane’s Firefox Hacks for this):

extensions.update.autoUpdate /* set to true */
extensions.update.severity.threshold /* set to 0 (lowest severity) */
app.update.autoUpdateEnabled /* set to true */
app.update.enabled /* set to true */

That didn’t work for me, presumably because there’s some sort of timer. It seems to me as if I’ve heard at some point that different versions of Firefox do their updates at different times once a week. But say I have an important security release for my extension and want to prompt people to upgrade immediately, whether they’ve just installed it two days ago or whether they’ve had their browser open for three weeks without a restart (a tempting method for checking updates would be on browser load).

Luckily, Firefox’s mechanism has interfaces exposed that allow you to tap into some of the functionality. Unfortunately, there’s not enough exposed to be extremely useful, but there’s enough to get by. Specifically, there’s a function available through the nsIExtensionManager component that allows you to display the extensions manager wizard, as follows:

var nsIUpdateItem = Components.interfaces.nsIUpdateItem;
var gExtensionManager = gomponents.classes[“@mozilla.org/extensions/manager;1”]
.getService(Components.interfaces.nsIExtensionManager);
var itemType=nsIUpdateItem.TYPE_EXTENSION;
//The guid here is the guid for the extension in question.
var items = gExtensionManager.getItemList(‘{e9f3a1cb-98a9-4384-879b-c6d1e39ef5bf}’, itemType, { });
var updates = Components.classes[“@mozilla.org/updates/update-service;1”]
.getService(Components.interfaces.nsIUpdateService);
updates.checkForUpdates(items, items.length, itemType, Components.interfaces.nsIUpdateService.SOURCE_EVENT_USER, window);

The trick, then, is to check the current and remote versions of the extension and to display the wizard only when there’s a discrepancy. Else you wind up showing a blank wizard. This is easily enough managed by querying the extensions RDF for the version number and then polling a remote script that serves up the current version of your extension (I use a different output source here than the updateURL RDF because all I really need is the number, and I want to conserve bandwidth. I could find no way to check the remote version using built-in interfaces without spawning the update wizard, though I may have overlooked or misunderstood some code. In pseudocode, the routine runs as follows:

  • Check a timer to see if we need to check for an update.
  • If so, query the extensions rdf to get the installed version number.
  • Check a remote file for the current version number of the extension.
  • If there’s a difference, use the code given above to pop up the upgrade wizard, which walks the user through the process.
  • Set the timer to now plus the update check interval.

Naturally, you kick this off in an onload handler so that any time your browser is started, it checks immediately for updates and then checks periodically for as long as the browser’s open.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s