Jetpack, Fennec and NativeWindow

Mobile Firefox add-on development is getting more and more relevant. As Firefox for Android steadily adds users and continues to be top-rated on Google’s Play Store we are also seeing increased traffic from millions of Android users on the Add-ons site looking for themes and extensions. We’re even running a contest to get developers interested in writing mobile extensions!

The trouble is, we don’t have that many add-ons, in fact as of this writing there are only currently 122 extensions that are compatible with Firefox for Android. I suspect part of the problem is that Firefox on Android is different:

  • There is no XUL on Android.
  • All addons on Android need to be ‘restartless’.

Needless to say, Mobile Firefox extensions are different, and so some developers may be a bit wary of jumping in with both feet. This post is a guide to show you some of the main capabilities available to you on Android in particular around UI integration and tooling.

Prerequisites

If you want to do Android-oriented development you’re going to need to install the Android SDK in order to get the Android Debug Bridge ( aka ‘adb’ ). Head on over to the Android developer portal and follow their install instructions, and be warned it is a hefty download.

If you don’t have an android device handy, it should be possible to run the Android emulator and install Fennec into it. In practice we’ve found this to be quite slow, using the arm emulator – one workaround might be to use the x86 emulator and x86 builds of Fennec, which are now available.

In both cases, you will need to enable ‘USB Debugging’ in the developer options – if you are running Jelly Bean ( 4.2 ) you will need to first read about the trick to get the developer options to show up in settings.

UI Integration

Integrating with the Firefox for Android ( Fennec ) UI is fundamentally different than with traditional XUL add-ons due to the use of Android’s native UI. To help with this, the Fennec team has provided extension developers with two global objects they can use to do common tasks: BrowserApp and NativeWindow.

BrowserApp is a utility object that allows you to enumerate, fetch, open and close tabs, interact with user preferences and even quit the browser! While there is no exciting UI or system integration here, BrowserApp provides key functionality in a simple and usable way. Some annotated code samples:

// Add a tab
let tab = BrowserApp.addTab();

// Log the titles of all open tabs
function logTabTitles(window) {
  var tabs = window.BrowserApp.tabs;
  tabs.forEach(function(tab) {
    window.console.log(tab.window.document.title);
  });
}

// Listening for tab events
function watchTab(aEvent) {
  // the target is a XUL browser element
  let browser = aEvent.target;
}

BrowserApp.deck.addEventListener("TabOpen", watchTab, false);
BrowserApp.deck.addEventListener("TabClose", watchTab, false);
BrowserApp.deck.addEventListener("TabSelect", watchTab, false);

More examples and documentation can be found on MDN.

NativeWindow is where all the cool kids hang out.

NativeWindow’s primary purpose is to allow developers to easily extend Fennec’s UI, via four key utilities:

  • menu: add items to Fennec’s main menu
  • doorhanger: user interactions via native doorhanger UI
  • contextmenus: exactly what you think it is
  • toast: not bread-related, but instead a light-weight way of doing native in-app notifications.
// Add a menu item
menuID = NativeWindow.menu.add(label, icon, callback);

// Show a doorhanger
NativeWindow.doorhanger.show(message, value, buttons, tabID, options);

// add a context menu item
menuID = NativeWindow.contextmenu.add(label, selector, callback);

// show a 'toast' notification 
NativeWindow.toast.show(message, duration);

Using the Add-on SDK

The Add-on SDK, which has built-in support for running and testing extensions with a device, as well as Fennec support for most relevant SDK modules. The great thing about this that if you are used to using the SDK, most modules will work as expected. For a complete of what is and isn’t supported, please see the documentation.

Deployment: just use cfx! You will need to add some mobile specific arguments to your cfx command-line though. To help with this, I’ve written a quick UNIX shell script that should help:

#!/bin/bash

cfx -b /usr/local/bin/adb --mobile-app=fennec --app=fennec-on-device --force-mobile -v -o $1

The above command-line assumes you are using a Firefox nightly build on your android device, other options include firefox, firefox_beta and fennec_aurora.

While there is no built-in support for NativeWindow in the SDK, it is pretty simple to get access to it and mix and match NativeWindow’s capabilities with those included already in the SDK:

// get a global window reference
const utils = require('api-utils/window/utils');
const recent = utils.getMostRecentBrowserWindow();

// show a Toast notification
recent.NativeWindow.toast.show("Hello world!", "short");

For more extensive examples of mixing the SDK with NativeWindow calls, check out my ‘Fennec+’ example extension on Github.

Click on the thumbnail to open a gallery in a new tab.

The Bare-bones Approach

If you’re more comfortable developing a restartless add-on Mark Finkle from the Firefox for Android team has created a great template as a Github repo to get you started. The template includes a full bootstrap.js implementation and examples of how to use NativeWindow and BrowserApp as well some simple scripts for building your extension and pushing it to a device or emulator via adb.

Pretty Pictures

To give you an idea what UI integration looks like on Android, I’ve added some screenshots to show off the various types of things:

Additional Resource

15 comments on “Jetpack, Fennec and NativeWindow”

  1. Robert Kaiser wrote on

    I for sure have not adapted my add-ons to Firefox for Android because there’s no XUL. And I also won’t adapt them unless I can use the familiar-from-the-web markup notation and can use the same code across desktop and Android. Right now, I’m pretty sure I’ll never adapt them, I probably will even abandon the desktop ones at some point and only do web apps, where the cross-platform web-like promise still exists.

    1. Jeff Griffiths wrote on

      Hi Robert,

      Thanks for the honest feedback! I’m very aware that some people used to XUL will simply not move on to our more JS-base, imperative direction both in Fennec and the SDK. I would counter that if you ever think of an idea for an add-on that is mobile-specific, maybe you’ll give this stuff a try.

  2. Jason Barnabe wrote on

    I *have* added support for mobile in my extension (Stylish), and I found two major stumbling blocks.

    1. You need to actually have access to a device.
    2. The documentation is poor. It’s not so much that the information isn’t there, but that there’s a lot of outdated information. I spent (wasted) a lot of time converting my extension to the electrolysis framework, only to find that this was, at best, not needed. For example, https://wiki.mozilla.org/Mobile/Fennec/Extensions/Electrolysis, is linked to from various other documents, blogs, forum posts, etc., but gives no indication that this was abandoned.

  3. kmaglione wrote on

    There is no XUL on Android.

    That’s not strictly true. Key parts of the Android UI, like the add-on manager, are XUL. In fact, XUL is required for add-ons that use inline options. There’s even a stub XUL window so that overlays still work from non-restartless extensions (although that’s nothing to celebrate). The bulk of the browser UI is written in Java, using native widgets, though, and is therefore not accessible to add-ons the way the XUL UI was.

    1. Jason Barnabe wrote on

      Also, not all addons on Android need to be ‘restartless’, as evidenced by the entries on https://addons.mozilla.org/en-US/android/extensions/?sort=users that don’t have the label.

      1. Jeff Griffiths wrote on

        Really? I thought we had a hard requirement for restart-less. Kris?

    2. Jeff Griffiths wrote on

      Sorry, I should have said:

      “XUL overlays cannot be used on Android.”

  4. Mindaugas J> wrote on

    Pardon, I’m an android n00b but it seems this post is misleading.

    I was not able to run arm emultion at all on my 64bit linux box. x86 images work but they are slow as hell especially Android 4+. Fennec crashes on Android 2.3, though. In any case, I couldn’t even access the preferences, forget about remote debugging: the about:config page loads but is not rendered at all (the thumbnail in the tab selection is accurate, though).

    So yeah, I would not say developing for fennec without Android device is happening any time soon.

    1. Jeff Griffiths wrote on

      I’ve been able to run the emulator on OS X, but I agree it is not a very good experience. I would say that x86 images are going to be *faster* than arm images actually, but x86 builds of Fennec are at best in a preliminary / alpha state.

  5. Alexufo wrote on

    can you help http://stackoverflow.com/questions/17170551/downloading-files-code-snippets-in-firefox-sdk-builder ?
    I didnt understand.

  6. Tom wrote on

    Please can you add a location bar icon system? Popping up a ‘doorhanger’ for every page isn’t a good experience.

    1. Jeff Griffiths wrote on

      That’s an interesting suggestion! As far as I’m aware, the native Java apis don’t allow this currently but you could suggest it by filing a bug:

      https://bugzilla.mozilla.org/enter_bug.cgi?product=Firefox%20for%20Android

  7. ac wrote on

    Would you put up an example to show how to build a simple jetpack extension which support both desktop and mobile?

    I have a simple extension which has a icon on the addon bar.

    It seems that we need to somehow test for the NativeUI (for android) at the startup and put a menu item for the fennec while put a icon to extension bar for desktop firefox.

    1. Jeff Griffiths wrote on

      I don’t have an example at hand that support both, however you can easily test which product you’re on using the xul-app module:

      https://addons.mozilla.org/en-US/developers/docs/sdk/latest/modules/sdk/system/xul-app.html

  8. Axel wrote on

    I am trying to convert (or rather rewrite) QuickPasswords to fit on the mobile platform, but having trouble with the imports. Could you make a more involved examples / skeleton that has a proper chrome / content structure, and an chrome.manifest? Not everybody likes stuffing all their code into bootstrap.js – I would really prefer the same structured approach that I have on my desktop addons.