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.
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:
Robert Kaiser wrote on
Jeff Griffiths wrote on
Jason Barnabe wrote on
kmaglione wrote on
Jason Barnabe wrote on
Jeff Griffiths wrote on
Jeff Griffiths wrote on
Mindaugas J> wrote on
Jeff Griffiths wrote on
Alexufo wrote on
Tom wrote on
Jeff Griffiths wrote on
ac wrote on
Jeff Griffiths wrote on
Axel wrote on