Trimming the Fat on Web View Based Applications

Trimming the Fat on Web View Based Applications

The use of web views for rendering application user interfaces is not a new concept, although methods for doing so have evolved over the years. In this article, I argue that you can re-use existing API’s to provide a web browser runtime instead of bundling one with each application you ship.

We can now see that platforms are bundling web view libraries and API’s, and this presents an opportunity to write applications that use C++ for performance critical tasks, HTML and CSS for displaying the user interface, and JavaScript to bind to native methods.

What Is Not Covered In This Article

Mobile operating systems like Android and Apple’s iOS both include native web views accessible from their respective first-class languages: on Android, Java, and iOS: Swift. I won’t go into those platforms, because I’m focusing on better alternatives to CEF which is, at the time of writing this, a desktop based runtime. I’ll be covering desktop platforms only.

Using and extending web views on these platforms is trivial, but it may be better to use native components instead of rendering HTML.

Facebook, for example, switched from HTML to native views, thereby improving performance, and led to the development of React Native, allowing JavaScript developers to create views using native components.

Bundling CEF With Your Application is Wasteful

I think that shipping ~200 megabytes for an application is wasteful, when you can use the readily available web view API’s for a platform. It should only be several megabytes.

Web Views in Windows

Microsoft, in 1999, released an HTML application runtime for the Windows operating system, called MSHTA. It provides facilities to make the window look more like a native application through certain XML tags, as shown in this example from Wikipedia:

<HTML>
<HEAD>
<HTA:APPLICATION ID="HelloExample" 
   BORDER="thick" 
   BORDERSTYLE="complex"/>
<TITLE>HTA - Hello World</TITLE>
</HEAD>
<BODY>
<H2>HTA - Hello World</H2>
</BODY>
</HTML>

MSHTA, wasn’t used much for applications, however.

Since then, they have provided a re-usable web browser ActiveX control, accessible through the COM API. However, this was for re-using Internet Explorer, and is no longer recommended.

More recently, Microsoft have provided API’s to re-use the Chromium version of Edge that is now bundled with Windows 10 by default, through WebView2.

This is important, because since the API’s for the Chromium based web view are bundled with Windows by default, it means that developers can use wrapper libraries to target Windows’ web view API without including CEF libraries.

In the next section I mention a C++ header file containing a wrapper class for the webkit2gtk-4.0 library. The same header also has a wrapper for Microsoft’s WebView2 library.

Web Views in Linux and GTK3

Today, CEF and it’s companion framework, Electron seem to be a popular choice for applications on Linux. However, there are much more readily available web view components. There exists a library, called webkit2gtk-4.0 that provides a GTK based web view, that can be embedded and a JavaScript engine that can be extended from C or C++ code.

The KDE project really were pioneers with web browser technology, using it in the desktop environment, and developing KHTML: the basis for Apple’s fork, WebKit, which is the engine powering Safari.

Over time, Apple had made changes that could not be merged with KHTML, so they formed and released webkit2gtk-4.0 separately. The library provides a standards compliant WebKit compatible browser.

With the latter statement in mind, there is not specific built in XML tags to affect the behavior of the browser

Targeting Linux and Windows

There’s a repository on GitHub called webview (https://github.com/webview/webview), which contains an important header file: “webview.h”. This header file contains the wrapper classes I’ve mentioned previously that provides a familiar interface to different platform’s native web view API’s.

Update: If you would like to extend the JavaScript engine for webkit in a more direct approach, some example source code is available here: https://github.com/vrruiz/WebKit-JavaScriptCore-Extensions

Here’s a sample program from that repository demonstrating the usage of that interface, by loading HTML, and adding custom bindings to the JavaScript engine:

//bin/echo; [ $(uname) = "Darwin" ] && FLAGS="-framework Webkit" || FLAGS="$(pkg-config --cflags --libs gtk+-3.0 webkit2gtk-4.0)" ; c++ "$0" $FLAGS -std=c++11 -g -o webview && ./webview ; exit
// +build ignore

#include "webview.h"

#include <iostream>

#ifdef _WIN32
int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
                     LPSTR lpCmdLine, int nCmdShow)
#else
int main()
#endif
{
  webview::webview w(true, nullptr);
  w.set_title("Example");
  w.set_size(480, 320, WEBVIEW_HINT_NONE);
  w.set_size(180, 120, WEBVIEW_HINT_MIN);
  w.bind("noop", [](std::string s) -> std::string {
    std::cout << s << std::endl;
    return s;
  });
  w.bind("add", [](std::string s) -> std::string {
    auto a = std::stoi(webview::json_parse(s, "", 0));
    auto b = std::stoi(webview::json_parse(s, "", 1));
    return std::to_string(a + b);
  });
  w.navigate(R"(data:text/html,
    <!doctype html>
    <html>
      <body>hello</body>
      <script>
        window.onload = function() {
          document.body.innerText = `hello, ${navigator.userAgent}`;
          noop('hello').then(function(res) {
            console.log('noop res', res);
          });
          add(1, 2).then(function(res) {
            console.log('add res', res);
          });
        };
      </script>
    </html>
  )");
  w.run();
  return 0;
}

By default, this implementation allows you to create bindings to anonymous functions, which then on the JavaScript side, behave asynchronously as promises.

Closing Remarks

I’ve provided a link to an example wrapper library for native web views, but there are undoubtedly more of them. In the future, it would be good to see applications utilizing them.

The wrappers need not be limited to C++: the above library also has bindings for Go.

I think the virtue of not repeating one’s self is overlooked for the sake of convenience or familiarity, but I think people you strive to do their best by not distributing redundant software if you can avoid doing so.

I understand that this article does not cover web view libraries in great detail, but if that’s something you would like to see, or if you have any other comments, please let me know.

Leave a Reply

Your email address will not be published. Required fields are marked *