Using a web technology stack to draw GUI has basically become a recognized solution with the most balanced cost-effectiveness. Whether it's desktop, mobile, or even the operating system you're using, there's an abundance of WebView. This "trend" started blowing a decade ago (counting on fingers—) when I was still a college student. Intel created something called XDK, and IBM even tailored its own embedded WebView engine called CrossWalk (although it's no longer maintained).

After so many years of development, developing hybrid applications with a web technology stack on mobile is still a very troublesome thing. There are two main reasons for this situation. On the one hand, Chromium itself is highly coupled with the Android system (there are some APIs in Android specifically for Chromium), the internal engineering practices are chaotic, and it's extremely difficult to trim. On the other hand, Android itself is highly fragmented, and various "developing countries" and "self-researched" "OS" will also cause trouble in various ways, such as the notorious MIUI, whose built-in browser seems to follow rules but pretends to be a higher version browser, and some community ROMs cut off some browser APIs for unknown reasons.

To address this issue, almost every "big company" has its own solution. ByteDance has its own tailored WebView; Tencent has two, one tailored by WeChat and another problematic X5. Some teams also single out parts of the web standard to use separately, like building a native binding for the WebGL standard to render some promotional pages.

However, because this part of the work is highly coupled with business logic, non of them has open-sourced their implementation. The only closed-source implementation, Tencent's X5, is also full of problems and practically unusable.

But there is still "hope for humanity" in the open-source community. Mozilla has made a componentized package of Firefox's engine and created a product called GeckoView that is somewhat usable.

Very few people know about this thing, and even fewer hybrid development frameworks have adapted it. But when we were working on an interactive video project, we really needed a feature that could control the version of the engine independently. So we went ahead and integrated it with Ionic. Hence, we now have @web-media/capacitor-geckoview.

README.md

First of all, the principle of this thing is to directly patch @capacitor/android, so the plugin version is forcibly bound with the Capacitor version. Our implementation only supports up to version 4.6.0. We've already patched the latest version, but the build isn't running through yet, and our group members are still working on it.

On the other hand, this plugin was not completed by me alone. The Android side was developed by Sun, and the web side was done by me and Hyper. I'm just here to provide a technical introduction.

Installing

If you want to replace Capacitor's WebView with GeckoView, the first thing to do is to change the package.json to parse the installation package, insert a field called resolutions, and write down this information:

  "resolutions": {
    "@capacitor/android": "npm:@web-media/capacitor-geckoview@2.0.0",
  }

Make sure your Capacitor version is 4.6.0, and that the version number of @web-media/capacitor-geckoview is locked at 2.0.0, otherwise, there is a high possibility of unpredictable bugs.

Next, configure your Ionic project normally, and in the generated Android project, make a small modification. Open android/build.gradle, find repositories under the allprojects section, and add the following configuration at the end:

        maven {
            url "https://maven.mozilla.org/maven2/"
        }

After this, you can sync and compile normally. There is nothing extra to configure, and theoretically, the development and integration of any native plugins should not be affected. The only thing that needs to change is the debugging method, from Chrome's developer tools to Firefox's debugging tools.

Technical Details

The overall architecture of Ionic/Capacitor is mainly divided into three layers: plugins, Ionic glue, and the web layer. These layers are very cleanly cut without any coupling, so modifying the middle glue layer should not have any impact on the other layers.

Specific modifications include:

Changes at the Android level

  • Replacement of WebView: Literally replacing the system's WebView with GeckoView.
  • Replacement of web file requests: Unlike the built-in WebView of Android and iOS's WebView, GeckoView itself cannot create a virtual file protocol or intercept file transmission. So we did some dirty work by directly opening an HTTP server on a random port for the WebView to access.
  • Injection of communication functions: Rebound the communication protocol between the plugins and the web container. Essentially, post messages are still flying back and forth, nothing special.

Modifications inside the web container

  • Implementing a plugin to inject scripts: Since GeckoView does not support direct script injection into pages (of course, other browsers do support this¯\(ツ)/¯), Hyper wrote a Firefox plugin to handle this issue separately.
  • Initialization timing issue between plugins and web content: We found that plugin loading is always slower than web content, which could cause early communication to be lost. For this, we modified the communication bridge in Ionic, creating a queue to cache all communications until the plugin is loaded and then send them all at once.
  • Data synchronization on random ports: Since the ports are random, there will inevitably be issues with cross-domain, localStorage synchronization, etc. This part is also handled with a little tweak at the plugin level.

Pitfalls

  • Because the need for Cookies is very rare in hybrid development scenarios, we did not implement this functionality. If you need it, you can submit a PR to add this part, which would require an additional SQLite for data storage.
  • On some extreme devices, the plugin may not be initialized when the application is first launched (suspected to be a bug in GeckoView itself), so we built in a timer. If the communication mechanism between Native and Web is not established within five seconds, the page will be forcibly refreshed. This situation is very rare, so you probably don't need to worry too much about it.
  • Again, the 5.7.0 patch currently has a bug, and Sun is dealing with it, expected to be resolved by next week.

If you encounter any problems while using this, please contact us in the issue area of @web-media/infrastructure. We will try to reply when we have time.

That's all, Happy Coding!