I’ve been experimenting with various web runtimes for running the system chrome of Webian Shell.
- Enable me to create browser chrome which can safely embed web content
- Provides an API to expose aspects of the content via methods and events (e.g. location and title changes, icons, app manifests etc.)
- Ideally be portable across desktop and tablet hardware as well as other form factors like TV and VR in future
- Provide a route to create an OS which boots directly to Shell without any other graphical applications running
Previously Webian Shell has used used XULRunner, Mozilla Chromeless and B2G from Mozilla, but all of these projects have now been discontinued. Gecko is no longer seen as a platform for building applications, just the back end of Firefox. This means it’s very difficult these days to build anything except Firefox with Gecko.
During the transition of B2G to the community I thought it would be possible for me to continue using B2G OS as a base, using the new simplified architecture we had created with a split between system chrome and system web services. Unfortunately all B2G code is now being ripped out of Gecko so that isn’t an option.
Since then, the runtimes I’ve investigated include:
- Android WebView
- React Native
Positron was meant to be an Electron-compatible app runtime for creating desktop apps based on Gecko. This would have been ideal for the desktop version of Shell, but unfortunately that project has also now been discontinued.
On the mobile side, GeckoView is meant to be a Gecko-based alternative to Android’s WebView. I experimented with creating a tablet version of Shell using GeckoView as part of an Android app. My idea was to use Android Things to boot to Shell as the only Android app running on a tablet device.
The downside of Electron is that it’s not really designed for writing browser applications. The Tofino team discovered some limitations when trying to prototype new desktop browser experiences. Some of these limitations aren’t so much of a problem for Shell, but it seems likely that at some point I’m going to come across a missing feature.
One example of a feature which Gecko has which Electron lacks is an event to tell the <webview> embedder when a manifest link relation is detected in a web page. This is needed by Shell to detect and install web applications. I filed a feature request for this but in the meantime the community suggested a workaround by using a “preload script” which allows you to inject a privileged script into web pages which runs before the content is rendered. I don’t really like this approach but it does provide a route for me to polyfill over missing features.
In terms of providing a route to booting an OS straight to Shell I discovered that resin.io has a template for booting Resin OS straight to an ElectronJS application. What’s particularly cool about this is that they have support for various IoT developer boards including the Raspberry Pi and apparently have support for touch events. As I’ve been trying to prototype the tablet version of Shell using a Raspberry Pi with a touch screen (for use as a smart home controller), this could be ideal. It would allow me to write both the desktop and tablet versions of Shell using the same runtime and share code between them. The question is how well this performs in practice, which is going to require some more experimentation.
As GeckoView is still quite immature I tried using the native Android WebView instead. This obviously works fine as an Android app, but I got stuck when I realised that Android Things on Raspberry Pi didn’t yet support WebView because it lacked OpenGL support. Trying to add a WebView to an Android app would just crash the app. Presumably this would also prevent me running a GeckoView based app on Android Things.
This bug has just been fixed so it should be possible to use WebView in Preview 5 of Android Things. But it would still mean a completely separate code base for the tablet version of Shell and I’m not sure the native Android WebView has all the features I need.
The “Quantum Browser Runtime” rose from the ashes of Positron with a less ambitious goal of providing a desktop application runtime using Firefox and existing Gecko APIs, rather than trying to be compatible with Electron.
The downside is that because Gecko is so tightly coupled with Firefox these days, qbrt includes a bit too much of Firefox in its current incarnation. This makes for a bulky download and weird issues like my application calling home to Mozilla for things because it thinks it’s still Firefox. These things may well be fixed over time, but qbrt still feels like a side project and I don’t have confidence that it’s going to stick around very long.
Technically Firefox is still using B2G’s Browser API which I need to create Shell and there is a vague plan to move Firefox from XUL to HTML over time, so my needs should be fairly in line with the long term plans for Firefox. But this plan is slow moving and while the “platform” team (now the Firefox back end team) is laser focused on the current needs of Firefox, anything that gets in their way gets ripped out of Gecko. For example, methods on the Browser API which were used by B2G to set the visibility of browser tabs to prioritise processes were removed without notice to make way for a new process priority manager in Firefox.
I really want to use Gecko for Webian Shell, but I’m finding the Firefox team are quite hostile to anyone except the Firefox team using Gecko to build things and it’s getting harder and harder to do so.
I haven’t yet come across any of the limitations of Electron that Muon is designed to fix, but I imagine that eventually I will. Also, I understand that the Kai OS team is using Muon to try to replace Gecko on B2G by porting Blink and Muon to the Gonk OS layer (basically the lower layers of Android). If they made that open source it would mean that there could be a path to running Muon-based applications on Android hardware in the future, which is quite exciting.
Electron has some limitations when it comes to building a browser and I’m not sure how well it will perform on touch based hardware compared with say a native Android app running on Android Things, and there’s currently no easy way to get it running on Android tablet hardware. Also, it would mean leaving behind Gecko which Webian Shell has been using from the start.
In an attempt to hedge my bets I’ve been trying to write a common layer of abstraction on top of both Electron’s <webview> and qbrt’s <iframe mozbrowser> HTML elements by creating a <webian-webview> web component with my own WebView API. This would allow me to support both Electron and qbrt with the same front end chrome code. This in itself was not easy because Gecko still doesn’t support Custom Elements or the Shadow DOM. I was able to achieve it using the webcomponents.js polyfill, although there’s a bug with that library which prevents my current implementation of the chrome from running in Gecko. I also created a startup script which can detect whether it’s running in Electron or qbrt and follow the correct code path accordingly. Whilst I like the flexibility of being able to run on both Gecko and Blink, this adds an extra layer of abstraction which will probably hurt performance in the long term and may get quite complicated as I get into more advanced features which are significantly different or simply missing from qbrt or Electron.
I think my overall conclusion is to start with Electron. Electron is well supported, comes pretty close to what I need and it provides an easy path to migrate to Muon and/or a potential KaiOS runtime in future. If Spidernode goes anywhere and Mozilla puts some real commitment behind a Gecko app runtime then I could potentially migrate back to Gecko in future, but for now it’s just too damn hard to use. The Electron approach might not work so well for touch-based devices if the Kai OS runtime doesn’t get open sourced as I suspect performance on Resin OS isn’t going to be great and I’ll have to implement my own on-screen keyboard which I’d probably get for free with Android Things. So I may keep experimenting with a native Android version or even using React and compiling to different platforms.