If you are an Android or an iOS developer you’ve probably spent countless hours debating whether cross platform frameworks are worth of your time. They are advertised as the El Dorado of app development. It reminds me of the good old WORA (Write Once Run Anywhere) promises. Aaaaa good days…

In any case, reality is harsh. Dreams do not come true that often and we have an inner instinct to doubt all advertisement. So, let's talk about the history of this effort and the three attempts at solving this issue. But first, let's frame the problem better.

Front-end development

The issue arises from the problem of presenting ideas to end users. Think of your mother using a digital service. It does not matter which service, but any person that is not a real tech guy that likes UNIX interfaces (something like find . -name '*.js' -exec grep -i 'string to search for' {} \; -print ) will probably need some front end to the service (for the record, I do like Unix interfaces).

That is why Xerox invented the graphical user interface. While they were the only one with a GUI there was no cross-platform shoot out. But, as the principle of human chaos goes (just made that up), several competing graphical environments were also “invented”.

Anyway, the issue is that an operating system (Linux, Android, Windows, MacOS, RedoxOS and so on) provides the means for interfacing with the graphics, audio and input pipeline and it is up to developers to come up with what we call widget toolkits that will know how to display the interface, make sounds and receive inputs.

Even on the desktop this is a problem. Some applications work on Windows, Linux and MacOS by utilizing widget toolkits that work across them all. Some well known are (at least for Linux users):

GTK — Gnome Toolkit

QT

WxWidgets

These provide the building blocks for applications like buttons, text views and so on. They worked somewhat nice but had its drawbacks like:

Native look and feel — how to not surprise the user about how its controls looked

Some ancient APIs coupled with specific graphics, audio and input systems

They did not render remote interfaces

So, in order to support a new platform you had to build the infrastructure of these toolkits into the drivers of the new OS. Being open source, that could involve some time and effort to convince the team to support a new platform.

With the World Wide Web though, a new need arose: displaying remote interfaces. That is, when you want to access a digital service running in a server far, far away, you'd need to send the interface to that person's computer. It all started with simple documents linked to each other (each link would download the next page) and it evolved to asynchronous interactions through AJAX, WebSocket, long polling and so on.

The thing is: today we use more remote interfaces than local one. All right, I haven't done a huge research about this so let me rephrase this:

Most services either have a remote interface or a remote backend to serve the local interface.

In order to participate in the world wide web developers needed to develop browsers that could render these static documents at first and then all the specifics of ECMA Script and so on.

First wave of cross mobile

Initially the idea of running the same code in different platforms was only possible by JavaScript, HTML and CSS in the mobile landscape. That is: a website in an app. Think like a thin wrapper around a browser.

Why would one want to do that? Well, as we discussed in the front end section, every platform has a component called a WebView: a view that renders JavaScript, HTML and CSS. So, with one code base we could have an application running inside each platform's WebView. Nice and dandy :)

Well, as it turns out there are some issues to this approach:

Which version of JavaScript is good enough for every platform?

How to interface with native features that are not exposed through a JS API?

Performance of this approach against real native apps?

New features of each platform as soon as they launch?

There are countless articles on the pitfalls of this kind of cross platform effort. Even though, they have evolved a lot and some big companies bet on them. Here is a very small list of possibilities:

The core idea here is that a browser already has its presentation toolkit. They already need to plug into the graphics pipeline, audio, input and so on. Developers would only need to speak the web language and then they would start building mobile applications all the same.

The NATIVE keyword

Well, the web experience is different from that of a native interface. To render everything at 60 frames per second is not easy and not every phone can do that under the WebView component. Animations start to become a bottleneck and other particularities start appearing that might make the webview route a no-go for many people.

The alternative is a transpiler. Yep, that is correct. It is not a typo. TRANSPILER (source to source compiler). We compile a source code to, quick guess, another source code :)

What? Why would anyone want to do that? Well, it is more common than most people think.

Typescript is a language that compiles to Javascript for example. But then again, why? Because you can add features or translate from one source to the other.

This approach was special because you can develop a website using something like react and then use react-native to transpile to native sources. So, your application coded with Javascript would have all the benefits of native rendering and so on.

In practice, when you code a text in an HTML react-native component, it will transform it into a TextView in Android. Holy moly… we've done it! Problem solved right?

Well, more or less. You still need to know about each platform specific needs if you want to interface with a system service or you need to debug things deeply.

Another issue is that somethings just don't translate well. I am a Brazilian and I've always heard the story that “saudade” does not have a word in English. What do we do when we want to express “saudade”? Well, we cheat. We translate it to a whole sentence that practically explains the meaning of “saudade” (for the curious, it is like saying “I miss you” but it is not actually the same thing).

Examples of frameworks that use this approach are:

React-native by Facebook

Nativescript

Xamarin

New Wave of Mobile Development

(Iron Flutter! Just kidding… internal heavy metal joke)

Some folks with a similar problem had already solved the problem of cross platform development a while ago. They were not developing static linking documents. They were solving real-time rendering of thousands of polygons. Who are they? Game developers.

Think about it: do you really think that people who develop games for the Playstation, XBox, Nintendo Switch and so on, have a different repository with a different source code for each platform? Do you think they develop targeting only one of them and then rewrite it all on a different language for the Steam OS for example?

The answer is no. More or less no ;)

Of course they must take into account specific features of specific platforms but most of their code base is targeted at a game engine. I'll leave some examples of game engines here. If you have the chance to quickly browse their “features” web pages you'll see the answer was here from the beginning.

They all follow a similar architecture:

There is always a language runtime (Java, C#, C++ and so on)

They plug real deeply into the platform specific graphics, audio and input APIs

They have tooling for generating a binary optimized for each platform

They DO NOT use the platform widget toolkit. When they start, they ask the system: give me a window and a canvas where I can take control, the rest is up to me. They have their OWN pipeline of graphics, text rendering, input handling and so on. It is like a FULL environment that runs atop the hosting platform.

Wait, wait, wait… what is the difference with the NATIVE toolkits? Well, this approach avoids the need to translate to a specific LANGUAGE or toolkit. It translates directly to the low level stuff (beneath the toolkit) and so does not have to work with any impedance.

Let's say that this is not a source to source compiler. It is a source to binary compiler. It focus on the ABI (abstract binary interface) rather than the API (abstract public interface).

That is why game engines are so performant. They can implement their own optimizations.

All right, now is the moment of truth: what if, instead of making a GAME engine we made an APPLICATION engine? By that I mean: we embed a whole graphics stack (Skia for example), a whole text rendering engine (HarfBuzz for example) and so on? With that we would be able to develop a runtime on top of that that can understand a single language for different platforms. As long as Skia and Harfbuzz can run on the platform, our runtime is safe.

This is the approach of Flutter. I hope you understand now why this is a different approach to current react-native for example.

Of course not everything is perfect. What is the size of my application if I embed all that? Well, it will certainly be bigger than if we made everything by hand on each platform. Not all system services have a common API for all platforms and so on. These issues will always exist on cross-platform solutions.

What we should look at is the advantages. With Flutter you get:

Hot-code deploy. No need to wait for Gradle to build anything. No need to worry with Instant Run and if it works with annotation processors.

A fresh approach to handling mobile events: screen rotation, state handling, application lifecycle and so on.

A new layout mechanism easier to reason about.

No need to worry about backwards compatibility :)

No need to worry about dex limit

So on…

What a good time to be alive… right?

Engine toolkit

If you read everything up to now you should be wondering: this flutter thing isn't like the widget toolkits from the section front-end? Well, yes and no. It is an extension of the same concept: let's plug on the system low level to provide widgets. It is an extension on how it plugs on the system and how it runs on the end, but it is similar in concept.

So, why haven't we used GTK or QT for doing that? Well, actually, some people have done just that.

We have other platforms being built everyday (remember the principle of human chaos) and some of them are using these toolkits plugged on drivers or graphics specifications like OpenGL, OpenGL ES, Vulkan and so on.

We've tried with web technologies because everybody needs a webpage. Now the browser will start speaking WASM (Web assembly). Maybe we can take these toolkits and runtimes to the web too.

To finish this up: the principle of human chaos says that we will always be inventing new things that aren't all that new. Most of the time we are re-inventing things from the past with a fresher head. It is like we knew this moment would have come and we've came full circle :)

If you liked this post… you know the drill.