Restartless Add-ons – Default Preferences

I saw a neat technique in Bug 564675 for creating default preferences in bootstrapped add-ons. Edward Lee posted a link to some code he uses for a bootstrapped add-on. Essentailly, the default preference branch is writable, but not permanent. This is a good thing for bootstrapped add-ons. The add-on should write it’s default preferences every time it loads and the preferences disappear when the session ends. The code looks like:

const PREF_BRANCH = "extensions.myaddon.";
const PREFS = {
  someIntPref: 1,
  someStringPref: "some text value"

function setDefaultPrefs() {
  let branch = Services.prefs.getDefaultBranch(PREF_BRANCH);
  for (let [key, val] in Iterator(PREFS)) {
    switch (typeof val) {
      case "boolean":
        branch.setBoolPref(key, val);
      case "number":
        branch.setIntPref(key, val);
      case "string":
        branch.setCharPref(key, val);

function startup(aData, aReason) {
  // Always set the default prefs as they disappear on restart

I haven’t tested to see if there is a clean way to remove these preferences when a bootstrapped add-on is disabled or uninstalled. The default preferences will likely still hang around until a shutdown occurs.

We’re starting to amass a sizable collection of code snippets for bootstrapped add-ons. I think a new section in the MDC Code Snippets area might be needed.

Restartless Add-ons – More Resources

After playing around with bootstrap (restartless) add-ons a bit more, I came to the point where I needed some extra resources in the add-on. For images, I could have stuck with the data: URI approach I mentioned previously, but I also wanted to add an options UI for my add-on. Turns out it was pretty simple. Thanks to Vlad for getting the ball rolling.

The trick I am using now is to programmatically add a resource: alias for my add-on. A resource: alias creates a handy way for you to create URIs pointing to resources, like scripts and images, in your add-on bundle. It’s pretty simple to add a resource: URI pointing to the add-on’s root folder or XPI bundle. Here is the code snippet taken from my bootstrap.js file:

function startup(aData, aReason) {
  let resource ="resource").QueryInterface(Ci.nsIResProtocolHandler);
  let alias =;
  if (!aData.installPath.isDirectory())
    alias ="jar:" + alias.spec + "!/", null, null);
  resource.setSubstitution("myaddonpackage", alias);

function shutdown(aData, aReason) {
  if (aReason == APP_SHUTDOWN) return;

  let resource ="resource").QueryInterface(Ci.nsIResProtocolHandler);
  resource.setSubstitution("myaddonpackage", null);

The isDirectory check is needed because it is possible for add-ons to be installed in folders or XPI bundles, which require the jar: URI syntax. The code adds a resource alias, after which you can use URIs like this:


In these examples, images and content are folders inside your add-on bundle. Now you can add URI-based resources to your install.rdf like this:


Yes, the em:optionsURL works just fine for providing an options UI in your add-on. I hope this tip gives you more help converting your traditional add-on to a restartless add-on.

Updated: I added the removal of the resource: alias on shutdown based on feedback from Nils in comments. Check out his link to some great bootstrap add-on information too. The part about stale caches after an add-on update presents a painful problem. Waldimir has also previously posted about the limitations of bootstrapped add-ons.

Firefox Mobile – Managing Profiles

Last week we were talking about the need for private browsing, or something like it, in Firefox Mobile. Even though you might not share your phone with other people, you might share a tablet – especially the “family tablet”, sitting there on the coffee table. Private browsing is an obtrusive system, at least as implemented in Mozilla, and it’s doubtful we could add it for Firefox Mobile in time for the upcoming release. Also, private browsing doesn’t really satisfy the sharing use case for tablets.

Firefox has the concept of profiles, which could be useful for sharing. From the Firefox Support site:

Firefox saves your personal information such as bookmarks, passwords, and user preferences in a set of files called your profile, which is stored in a separate location from the Firefox program files. You can have multiple Firefox profiles, each containing a separate set of user information. The Profile Manager allows you to create, remove, rename, and switch profiles.

The built-in Profile Manager, used in desktop Firefox, isn’t really a good fit for mobile, so I made a simple, restartless add-on for managing profiles in Firefox Mobile, called Mobile Profiles. From the Preferences panel, you can add, remove and switch profiles.

I’m thinking about adding support for password protecting profiles and clearing private data when closing Firefox. Let me know what you think.

Development Details

I found the restartless, bootstrapped system I have been playing with worked well for this add-on. The nsIToolkitProfileService handles most of the heavy lifting. The UI is a little more complicated than my original trivial example, but I still only have two (2) files in my XPI. View the source here.

Without XUL overlays, I had to add the UI using DOM operations (createElement and setAttribute). Not a big deal, but it got tedious, so I made a little helper function:

function $x(aDocument, aElement, aAttributes) {
  if (typeof(aElement) == "string")
    aElement = aDocument.createElement(aElement);
  for (attribute in aAttributes)
    aElement.setAttribute(attribute, aAttributes[attribute]);
  return aElement;

Using this helper means adding elements via DOM is a little less syntax:

let itemManage = $x(window.document, "setting", {
  "id": "prefs-mobileprofiles-profiles",
  "title": "User Profiles",
  "desc": "Add, remove or switch profiles",
  "class": "setting-group",
  "type": "control"

I could probably make the helper function be a little more useful by adding some features you’d find in HTML DOM builders, but it’s good enough for now. I’ll probably add a chrome.manifest so I can support normal localization using properties files.

Bootstrap Jones – Adventures in Restartless Add-ons

We recently landed some code in Firefox Mobile to better handle restartless (bootstrapped) add-ons. Turns out, Dietrich made a non-Jetpack add-on using the SDK and tried unsuccessfully to install it into Firefox Mobile. In the process of getting everything working, I decided to make a simple restartless add-on we could use as a testcase. It’s a copy of Dietrich’s original add-on, without any SDK usage. I’ve not taken the SDK plunge yet. The experience was interesting, educational and slightly enjoyable. The process of testing the install / uninstall and enable / disable mechanism without a restart left me as giddy as a schoolboy.

I’ve decided to approach any future add-on development using the bootstrapped system. If I find a reason why it’s not possible, them I’ll switch back to the traditional XUL overlay approach. Below is the code from the testcase I created. There are only two (2) files! install.rdf and bootstrap.js. That’s it!

The install.rdf has the basic stuff along with the em:bootstrap flag that turns on the magic. My bootstrap.js file has the basic bootstrap methods, but only two, startup and shutdown, needed to be implemented. I added some code to handle adding and removing my add-on UI on demand. All I do is implement the loadIntoWindow and unloadFromWindow methods. Pretty easy, especially for lightweight add-ons.

Notice how I am using a data: URI for a button image, so I don’t need to package the file and add a chrome.manifest.

Just to be clear, I am not using Jetpack or the SDK. Firefox Mobile doesn’t really support Jetpack yet. This is just a simple bootstrapped, restartless add-on. I’m in the process of using this system for a bigger add-on, so I might need to make some adjustments. I’ll let you know how it goes.


<?xml version="1.0"?>
<RDF xmlns="" xmlns:em="">
    <Description about="urn:mozilla:install-manifest">
        <em:name>Bootstrap Jones</em:name>
        <em:creator>Mark 'Bootstrap' Finkle</em:creator>


var Cc = Components.classes;
var Ci = Components.interfaces;

function loadIntoWindow(window) {
  if (!window) return;

  // Get the anchor for "overlaying" but make sure the UI is loaded
  let forward = window.document.getElementById("tool-forward");
  if (!forward) return;

  // Place the new button after the last button in the top set
  let anchor = forward.nextSibling;

  let button = window.document.createElement("toolbarbutton");
  button.setAttribute("id", "tool-homebutton");
  button.setAttribute("label", "Home");
  button.setAttribute("class", "button-control"); = "url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAAo0lEQVR42u3VMQrCMBSA4Q7uOnsNB4%2FR0cM6ZPYyyRRIGhAzly5CNQrfD49Alhe%2BJdMkSZIk6d1ijMdSyryelNJp710hhMPWrpzzeRjAsiyX1tpzPf3%2B%2BgnsrV211hsAAAAAAAAAAAAAAAAAAAAAAACA0QDfHAAAAPweQH%2FUo5%2F3PafvCn4BAAAAAAAAAAAAAAAAAAAAAAAAAADGAkiSJOmPewEpGDS2TaImnAAAAABJRU5ErkJggg%3D%3D)";

  button.addEventListener("click", function() {
  }, false);

  anchor.parentNode.insertBefore(button, anchor);

function unloadFromWindow(window) {
  if (!window) return;
  let button = window.document.getElementById("tool-homebutton");
  if (button)

 bootstrap.js API

var windowListener = {
  onOpenWindow: function(aWindow) {
    // Wait for the window to finish loading
    let domWindow = aWindow.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowInternal || Ci.nsIDOMWindow);
    domWindow.addEventListener("load", function() {
      domWindow.removeEventListener("load", arguments.callee, false);
    }, false);
  onCloseWindow: function(aWindow) { },
  onWindowTitleChange: function(aWindow, aTitle) { }

function startup(aData, aReason) {
  let wm = Cc[";1"].getService(Ci.nsIWindowMediator);

  // Load into any existing windows
  let enumerator = wm.getEnumerator("navigator:browser");
  while (enumerator.hasMoreElements()) {
    let win = enumerator.getNext().QueryInterface(Ci.nsIDOMWindow);

  // Load into any new windows

function shutdown(aData, aReason) {
  // When the application is shutting down we normally don't have to clean up any UI changes
  if (aReason == APP_SHUTDOWN) return;

  let wm = Cc[";1"].getService(Ci.nsIWindowMediator);

  // Stop watching for new windows

  // Unload from any existing windows
  let enumerator = wm.getEnumerator("navigator:browser");
  while (enumerator.hasMoreElements()) {
    let win = enumerator.getNext().QueryInterface(Ci.nsIDOMWindow);

function install(aData, aReason) { }

function uninstall(aData, aReason) { }

Firefox Mobile – A Few Add-ons

In addition to working on Firefox Mobile, I like to tinker around with building add-ons too. Not surprising I guess, since I seem to go on and on about how to build them.

Anyway, I have a few add-ons that you might find useful – either installed in Firefox Mobile or as examples you can rip apart and use to build your own add-ons.

Mobile Tools

Mobile Tools is a collection of a few utilities that might be useful when debugging mobile webpages. You’ll find commands for viewing page source and basic page info. Both open in new tabs. Page source shows the web page’s raw HTML content. You can zoom and pan through the source just like any other web page. Page info shows some simple bits of information about the web page:

Mobile Tools also supports window.console a little better than the built-in native support, including:

  • String formatting in logging methods (%s, %d, %i, %f)
  • dir and dirxml
  • Simplified trace
  • group and groupEnd
  • time and timeEnd

Start Page Plus

The built-in start page, Firefox Start, is pretty, loads fast and has some nice features. We can always add more! Start Page Plus adds a few sections to the standard Firefox Start page:

  • Favorites: A list of bookmarks you want displayed on the start page. Just tag a bookmark with “start” and it appears on the start page.
  • Local Search: Quickly find various types of places near you with a simple tap. Includes food, hotels, gas, movie theaters and your own location – shown on Google Maps. This feature does use the built-in geolocation feature.
  • Local Twitter: Shows tweets happening near you. You don’t need to be logged into Twitter. The stream is based on your location.

Use the add-on options to show and hide sections as well as move them around the page. You can also set the zone used to pull in tweets from Twitter.

Firefox Mobile and window.console Support

Desktop Firefox added native support for a subset of the window.console API. It’s a subset in that only the following API methods are supported:

  • console.log(arguments)
  • console.warn(arguments)
  • console.error(arguments)

Also, the Firebug string formatting features are not supported yet.

Last night we turned on basic support in Firefox Mobile too. It’s basic in the sense that the window.console is merely forwarded to the Error Console.