Perhaps you've heard about Flutter lately. It’s a pretty hot topic in mobile development, specifically cross-platform mobile development.
"Oh, another cross-platform solution? This is becoming like all those new JS frameworks", you might think. It was my first reaction and probably the reaction of many others.
Don't judge too quickly though because Flutter is not “another solution”.
It’s a new approach.
Let’s take a look at how cross-platform mobile development evolved.
Android and iOS SDKs were both published in 2008. Apps developed with these SDKs are usually called “native apps”. Already in 2009, the first cross-platform solution appeared — PhoneGap. You might’ve heard of Cordova, that’s basically the core of PhoneGap that’s open-sourced.
Making an app with Cordova is like making an app that’s a web browser that only opens your page. It doesn’t deliver the best user experience a native app can do and that’s why both Google and Apple are not really fans of these apps flooding their stores.
Then there's Ionic, which uses Cordova as a core. Introduced in 2013, it’s a better, well-rounded solution packed with modern JS frameworks. The downside is that it has the same limitations.
Moving on to...
Native-bind solutions: React Native, Xamarin
In 2009, we also see the start of a different kind of cross-platform development. Around the same time, a lesser-known solution was introduced – Appcelerator Titanium. Instead of just showing everything as a web page, it can show native views just like native apps.
For example, in Titanium you can write
<Label>Hello World</Label> (yes, you can write in HTMLish) and this would use
UILabel on iOS and
TextView when running on Android.
At first, this looked great. You’re writing your code once and it works just like a native application on both platforms. No wonder other solutions decided to use a similar approach.
The first one to follow into the steps of Titanium was Xamarin in 2013 (later acquired by Microsoft). After Xamarin, React Native came out in 2015. As I write this, React Native is the most popular cross-platform solution.
Overall, native-bind solutions didn’t prove they could do what all cross-platform development want to do – write the code once and run it on multiple platforms.
It can work for simple cases, like the binding of that label in Titanium. But for any real-world app, bindings are not always that straightforward and what you end up with is being able to share only the business logic part of your codebase, and writing separate UI for each platform.
One example is the good ol’ button. In Android, there is no border property to change it for the button. Instead, you need to use shape XML, so you need reimplemented native views or custom renderers to overcome this limitation. This was really tricky for Xamarin which tried to support all kinds of platforms besides iOS and Android, like Windows Phone and Tizen OS.
That’s why it is not only difficult but also not advised to write UI for two platforms. React Native has a philosophy of “Learn once, write anywhere,” which means often you’ll write UI part of your code two times for both platforms.
Xamarin also isn't advised for advanced apps that require native feel or custom UI:
Flutter – a UI framework not trying to replace native development
How do native apps draw to screen anyway? Well, they are all just drawing graphic primitives on a canvas - think tiny lines, circles, and rectangles. TextView and UILabel are drawing text on the canvas and extending View or UIView.
The native-bind solutions (React Native, Xamarin…) have abstraction on the level of view, e.g. Label will be TextView or UILabel. Flutter works on a different level, the canvas is abstracted. When you use Text, that view (or widget as it is called) is rebuilt from the ground up by the Flutter team on this new abstracted canvas. It will look the same in both apps since all canvas operations work the same.
In fact, every component is rebuilt from the ground up on that new canvas. This was the only way to achieve a true cross-platform way of “writing once, running everywhere”.
For the Flutter team, this also meant that they need to copy the look and feel of native apps into their new rebuilt components. For example, Android TextView has 14k lines of code and all its behaviors had to be recreated from the clear canvas in this new Text widget. Every component like button, checkbox, switch, app bar and even scroll behaviors are copied down to pixel-perfection.
One might conclude that drawing in Flutter is the same as what the now deprecated Adobe Flash or game engines like Unity are doing. It’s true that they both take the whole canvas and then work in a way that can run the same code and draw to that canvas (whichever platform it is).
But they were never about mobile phones. Flash performance was notoriously bad so it was restricted on iOS way back in 2010. Unity started on desktop and struggles with resources on mobile.
The time is right for Flutter
Flutter came just at the right time. The idea of compilation to ARM and machine code, LLVM compiler, and using the Dart engine with all the performance optimizations and memory management makes it possible to finally achieve a native look and feel on mobile while writing once.
It has been in development for a few years now – in December 2018, it hit 1.0. The only thing that’s missing now is wide adoption.
Almost all developers have heard about React Native, but not that many have heard of Flutter.
The difference is even bigger for non-developers, like business stakeholders. Since the industry is talking about native and React Native, they can see Flutter as a risky new technology. But bear in mind, React Native was once also in this state. In case you need more than a hunch to believe 2020 could be the year when Flutter takes off, here’s a bone to chew on – it has already passed React Native in stars on Github, signaling strong popularity.
The art director of the cover illustration is designer Marijana Šimag.