A quick Flutter

Posted by Stuart on April 30, 2022 · 7 mins read

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:

  • Ionic and Apache Cordova
  • React Native

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.)

What I want for native app development

So what I am after is something similar, but for mobile, i.e.:

  • A dynamic language to expression control, logic, and everything I need to do
  • A thin but considered layer that smooths over differences between native components
  • Ability to drop down to direct native when needed

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.

And this is where options like Flutter, and Ionic, Cordova, React Native, and NativeScript all aim to provide a platform for developers like me.

Flutter

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.

Cordova, Ionic, and friends

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.

But what if we want to add some extra native logic? Well, these platforms allow us to use plugins that may include Objective C, for example, or we can simply package in some of our own Objective C code. But the rest of our application is more or less standard JavaScript. Ionic adds a new platform for that, Capacitor, where Cordova has a decent, solid, plugin system, but more dependent on community support.

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.

React Native

React Native goes the exact opposite direction. While it looks superficially like a web application framework, the display components are purely native. Layout and styling have a kind of CSS-like layer, but it’s more for convenience than an accurate picture of how it works. HTML is entirely gone, and replaced by more or less direct access to native components. As with Cordova, the control and logic is more or less standard JavaScript. However, unlike Cordova, it’s native components, so we can, for example, deploy to devices like an Apple TV without a web view.

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

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.

A sort of summary

  Flutter Ionic/Cordova React Native NativeScript
Web outputs Yes (but awful) Not really Yes (but awful) No
Live reloading Yes Yes Yes Yes
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
Control language Dart JavaScript JavaScript JavaScript
Architecture Specific to Flutter Angular, Vue, React React Angular, Vue, Svelte, React
Origin Google Apache Facebook 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.

And a personal summary

And no, I didn’t especially like Flutter, in the same way I didn’t like Adobe AIR. For this small app, I’ve switched over to NativeScript, which gives me some native UI and familiar JavaScript, and Svelte as a framework, while also opening up to Capacitor for extensions.