Android add-ons don't have to be restartless, but with Firefox for Android you can't use XUL overlays to create your user interface, so there's much less incentive to write overlay-based add-ons.
Restartless add-ons must contain a file named bootstrap.js
to handle initialization and cleanup. In this guide we'll present a template implementation of bootstrap.js
that simplifies initialization and cleanup tasks such as adding and removing the add-on's user interface.
To read more about restartless extensions (also known as bootstrapped extensions), refer to the bootstrapped extensions documentation.
If you are using add-on SDK, to read about Listening for Load and Unload.
bootstrap.js
The bootstrap.js
file must contain implementations of two functions: startup()
and shutdown()
.
startup()
startup()
is called by the host application when the add-on is installed or enabled, or when the host application is launched.
Inside startup()
the add-on should put all the code needed to initialize the add-on, including any code to construct persistent user interface elements like menu items.
shutdown()
shutdown()
is called by the host application when the add-on is uninstalled or disabled, or when the host application shuts down. Inside shutdown()
the add-on needs to undo any persistent changes it's made.
Template code
Here's a version of bootstrap.js
that implements startup()
and shutdown()
:
const { classes: Cc, interfaces: Ci, utils: Cu } = Components; Cu.import('resource://gre/modules/Services.jsm'); function loadIntoWindow(window) { if (!window) return; // Add any persistent UI elements // Perform any other initialization } function unloadFromWindow(window) { if (!window) return; // Remove any persistent UI elements // Perform any other cleanup } 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("UIReady", function onLoad() { domWindow.removeEventListener("UIReady", onLoad, false); loadIntoWindow(domWindow); }, false); }, onCloseWindow: function(aWindow) {}, onWindowTitleChange: function(aWindow, aTitle) {} }; function startup(aData, aReason) { // Load into any existing windows let windows = Services.wm.getEnumerator("navigator:browser"); while (windows.hasMoreElements()) { let domWindow = windows.getNext().QueryInterface(Ci.nsIDOMWindow); loadIntoWindow(domWindow); } // Load into any new windows Services.wm.addListener(windowListener); } function shutdown(aData, aReason) { // When the application is shutting down we normally don't have to clean // up any UI changes made if (aReason == APP_SHUTDOWN) return; // Stop listening for new windows Services.wm.removeListener(windowListener); // Unload from any existing windows let windows = Services.wm.getEnumerator("navigator:browser"); while (windows.hasMoreElements()) { let domWindow = windows.getNext().QueryInterface(Ci.nsIDOMWindow); unloadFromWindow(domWindow); } } function install(aData, aReason) {} function uninstall(aData, aReason) {}
loadIntoWindow()
To use this template you just implement loadIntoWindow()
to initialize your add-on. You can use the window
argument to access the NativeWindow
and BrowserApp
objects, which you can use to add user interface elements and interact with the browser.
For example, the loadIntoWindow()
implementation here initializes an add-on that remembers the URL for the last closed tab, and adds a menu item to reload that tab:
var nativeWindow; var browserApp; var menuId; var lastURI; function rememberURI(event) { let browser = event.target; lastURI = browser.currentURI.spec; } function reopenTab() { if (lastURI) browserApp.addTab(lastURI); } function loadIntoWindow(window) { if (!window) return; nativeWindow = window.NativeWindow; browserApp = window.BrowserApp; menuId = window.NativeWindow.menu.add("Reopen Tab", null, reopenTab); browserApp.deck.addEventListener("TabClose", rememberURI, false); }
unloadFromWindow()
Conversely, you implement unloadFromWindow()
to remove any UI elements and perform any other cleanup. To clean up the example add-on above we could implement unloadFromWindow()
as follows:
function unloadFromWindow(window) { if (!window) return; nativeWindow.menu.remove(menuId); browserApp.deck.removeEventListener("TabClose", rememberURI, false); }