Running Webextensions on Android with Geckoview
The new Firefox Preview for Android uses Mozilla's Geckoview to replace Android's standard Webview component. This enables a fully Gecko-based browser, but without the bloat of much of the Firefox desktop codebase, that the original Firefox suffers from. We can expect a much faster and cleaner browsing experience thanks to these changes, and the Geckoview and Mozilla Android Components libraries offer exiting tech for developers of Android apps that require some kind of Webview or browser functionality.
However, one thing missing from the Firefox Preview MVP are browser extensions. The availability of extensions on the original Firefox for Android has long been it's USP compared to other Android browsers. While the Mozilla Android team have not been working on Webextension compatibility, a lot comes for free with Geckoview, and the android components browser Engine abstraction also already contains a method to installWebExtensions and this is implemented in the Geckoview implementations. What that means is that Webextensions can be run in Geckoview on Android, and this post will show how to do it.
Installing the extension in your Android project
- Unpack the extension (if it's a
.xpiyou can extract it as a
.zip) in to a folder. This folder should have a
manifest.jsonfile in the root, and contain all the sources for the extension.
Move this folder into the
assetsfolder of your Geckoview app:
mkdir -p ./app/src/main/assets/addons mv /path/to/extension ./app/src/main/assets/addons/
Now, in your app, after you load your
Engineinstance, you can simply install the extension as follows:
// Engine creation val engine = EngineProvider.createEngine(context, settings) // Install addon engine.installWebExtension( addonId, // addonId must be constant to ensure storage remains across restarts "resource://android/assets/addons/extension" )
You can further check if the installation was successful by passing callbacks to the install operation.
Debugging the extension
Extensions can be debugged on a connected computer using Firefox Nightly, in the same was as was previously possible in Firefox for Android. You can enable debugging of the Gecko engine simply by setting
engine.settings.remoteDebuggingEnabled = true. In the reference-browser this option is expose in the app settings. Once enabled, and the device is connected to a computer, the device should be visible in
about:debugging in Nightly:
After connecting and selecting your device, you should be able to see various debuggable contexted, such as your currently open tabs and service workers. To debug the extension go to the very bottom and inspect the Main Process:
The last step is to chose your extension document in the dropdown on in the top right. This allows you to debug in the context of your extension background script.
Now you can debug as you would on desktop!
I mentioned at the start that a lot of extension compatibility 'comes for free'. Thanks to patches from my colleague chrmod to specifically fix
webRequest APIs, most common use-cases are covered now in the Nightly Geckoview build. One compatibility caveat is that all UI APIs do not work, as the hooks to handle concepts like page and browser actions should be handled on a per-app basis.
bookmarks– Not supported (
browserAction– Not supported
browserSettings– Partial. Some settings are not applicable and reject when accessed.
browsingData– Partial. Some functions missing (
removeHistory), and others do not return
contextualIdentities– API is present, but throws
"Contextual identities are currently disabled". May work if the preference is enabled in
find– Not supported
history– Not supported
menus– Not supported
notifications– API is present and responds as if successful, but no notifications are shown.
pageAction– Not supported
openOptionsPagethrows for example.
search– Not supported
sessions– Not supported
sidebarAction– Not supported
tabs– ✔ (
tabs.createrequires a handler on the app side)
topSites– Not supported
windows– Not supported
This means that most of the core is there, minus UI APIs. Also, as history and session storage is separate from the Webview, APIs based on access to this information do not currently work.