Today, I thought I’d have a quick Flutter.
I’ve built a few different ‘native’ applications using cross-platform techniques over the past few years, including:
But, with Flutter now being in play, I thought I’d review my options, and see which seems to be the best fit for my current needs and preferences.
For the most part, what I want in a way to build native applications is a vaguely portable set of UI components, and a language that quickly lets me assemble them into a product that looks and feels native to the environment.
Strangely, the actual best experience I had building portable native applications, many many years ago, was using Procyon Common Lisp. Procyon Common Lisp had a beautifully designed layer, ‘Common Graphics’, that was sufficiently planned you could build applications for both Windows and Macintoshes, back in the Windows 3.1 era (i.e., the early 1990s).
Common Graphics was so central to our deployment at the time, that the company I worked for acquired the whole Procyon company entirely, and sold its excellent Lisp for Windows to Franz Inc. around 1991, while retaining full rights to use it internally. I even built a fair few parts of the Windows Lisp, so we could bring our products out on Windows more speedily. Procyon’s Common Lisp for Windows metamorphosed into Allegro Common Lisp for Windows, and Common Graphics remains part of it to this day. The Mac variant, not entirely surprisingly, has fallen away – it was, after all, developed long before macOS OSX became a thing.
The advantage of Common Graphics was that it abstracted away differences, so you got a real Apple menu bar, or a real Windows menu bar, depending on your platform. You do lose a little fine-grained control, but it genuinely feels native, because underneath, it is native.
If you want, you can look at some (old) Common Graphics code, as it was used in
production, in our visual cognitive modelling language, Hank.
Generally, anything there in the Lisp package
CG was Common Graphics.
The result was: we could build a more or less native application, in Lisp, with platform look-and-feel, for both Windows and Macs. (You may think Lisp was hideously big as a language, some were concerned about that: the reality was this application used about 1Mb of memory, and maybe 2Mb of disk, when deployed.)
So what I am after is something similar, but for mobile, i.e.:
Debugging is key to this: I want an environment where I can make changes and immediately interact with them. I admit it, I’ve been spoiled by web technologies the same was I was with Lisp environments all those yeas ago.
Flutter is Google’s approach. It uses Dart as its main control language, and provides its own UI components. For Android, it’s very good. For iOS, it initially looks like it’s Android, i.e., material design is the default.
In theory, Flutter can build for web too, but by default it does so in an unusual way – it renders to a canvas rather than a normal set of elements. That provides extremely precise layout control, but at a price: what you’re working with is not exactly web technology. CSS and layout aren’t used.
And although there is an HTML renderer, it is not exactly conventional HTML. It uses web components, which can have tiny canvas elements inside for display. It’s not the HTML your grandparents would have used.
In a way, that’s not a big surprise. After all: we may be building apps for a platform that doesn’t use CSS, so we should expect CSS there anyway. For example, Apple TV’s operating system doesn’t include web views at all, so CSS can’t really apply.
It’s quite an achievement, but Flutter reminds me a lot more of Adobe Flash and Adobe AIR than conventional native applications. If you need pixel-precise rendering across platforms, it’s great. On the other hand, it’s a big ecosystem all to itself, and it feels like there’s a real risk of getting locked into it. Switching away from Flutter, for example, would involve a complete rewrite of every single thing.
The Apache Cordova/Ionic approach is a bit different. It depends much more on web components, even on mobile. In many ways, it’s a way of making a small single-page application run as if it’s a native application. So, for these technologies, HTML and CSS are far more important. And, therefore, some platforms like the Apple TV are out of reach.
You can choose from a few options to write the SPA part of your application. When I first used Ionic, it mostly used AngularJS, but now Angular, React, and Vue are all available options.
Underneath it all, though, your app is running on Safari-like or Chrome-like web view, and it’s a set of web styling layers that allows you to model the appearance on a native device. But, like Flutter, it’s not really using native display. Unlike Flutter, it is using moderately standard web techniques underneath, though.
For display control, React Native uses something almost entirely, but not quite, like CSS – it even there it is somewhat more like a single file component than traditional React, although with an awful JSXified syntax.
React Native’s big win is Expo, which allows apps to be debugged and developed on native (and web) devices with far less deployment misery than via, for example, Xcode. This means no need, for example, for developer subscriptions on Apple.
NativeScript is closely similar to React Native, although without being locked to React. In fact, you can choose between several basic architectures. At the moment, I’m enjoying Svelte, so I can use Svelte to write my native application, which is fine by me. I get all the native components, but I can share logic, stores, and so on, with a regular web application.
As with React Native (and unlike Cordova), there is no deep dependence on HTML views, which leads to a noticeably smoother user experience, and fewer odd display effects inherited from Safari.
There has been some work on integrating Expo links to NativeScript, but it is not well-developed yet.
NativeScript does make some attempt to use CSS, but there are some components where it really doesn’t work, and you have to use properties directly.
|Web outputs||Yes (but awful)||Not really||Yes (but awful)||No|
|Viable without HTML views||Yes||No||Yes||Yes|
|Debugging||Specific tools, e.g. VS Code plugins||Web cross-device||Built-in developer menu||Remote through VSCode|
|Packaging||Custom||Customized Webpack||Custom (Metro)||Customized Webpack|
|Display||Portable runtime||Web styling/CSS||Native UI||Native UI/CSS|
|Architecture||Specific to Flutter||Angular, Vue, React||React||Angular, Vue, Svelte, React|
|Origin||Apache||OpenJS (incl. Google, IBM, MS)|
So, it does depend on what you want. If you want a quick way to develop an application that looks smooth, and handles a wide range of devices, including non-mobile apps and web, Flutter is an option. If you want deep native access and the sharpness and gloss that provides (and believe me, I noticed the difference in feel) then React Native and NativeScript will have the edge.
But it’s important not to over-emphasize the differences. Ionic/Cordova, React Native, NativeScript in particular, have a lot in common. Flutter, to me at least, felt like it had more in common with a Java-like version of Adobe’s AIR than with any of the others. It does have similar aims, too: targeting standalone desktop apps as well as mobile. (Although it’s worth remembering that, conceptually at least, Ionic/Cordova has a lot in common with Electron-based applications – in fact, it more or less is a modified Electron, hence the flexibility in web technology.)
Here’s how I’d sum the options up:
Do you want to target desktop and web with the same build? Use Flutter, Ionic, Cordova, or accept the misery of parallel apps. Of course, with Electron, desktop has long been relatively easy to target using the Ionic/Cordova strategy of CSS and a collection of API plugins.
Do you want the gloss of native UI? Use React Native, or NativeScript if you don’t like React.