Just another cross platform mobile development framework?
I approached Flutter with some scepticism.
After all, there have been quite a few other cross platform frameworks that have promised, yet failed to deliver in the past. I preface the following opinions by saying that I am a native Android developer that has also dabbled in iOS.
Having been disappointed with previous cross platform frameworks, I was preparing myself for another let-down due to issues such as:
- UIs that don’t look or feel quite the same as a native app
To understand what Flutter has to offer I have done the following:
- created a Flutter Proof of Concept with authentication and simple user management, invoking native platform features (eg. SMS messaging)
- learnt some Dart
- analysed some of the source code of sample apps and widget libraries
- read Flutter blogs
- watched Flutter presentations from Google I/O, DartConf and others
The results are a positive surprise. This is the first time I feel that a genuine contender for cross platform mobile development has arrived that can attract native mobile developers.
Beyond this, I’m genuinely excited that Flutter could eventually replace developing in Android natively for the most part, as it provides such substantial productivity gains.
Note that Flutter is still in beta.
Why has Flutter caught my attention?
Flutter caught my attention for the following reasons:
- UI widgets that look and feel native
- High performance cross platform, react inspired framework
- Super fast debugging with stateful hot reload
- Additional features which I’ll discuss below
UI widgets that look and feel native
Flutter is unlike most other cross platform frameworks before it, in that it only interacts with the underlying hardware platform at the canvas level. The canvas is a low level abstraction of the mobile device’s screen, close to the underlying graphics hardware, and access to it is fast. Every Flutter onscreen widget has been re-implemented from the ground up to match Android’s Material Guidelines (Material widgets) and iOS’s Human Interface Guidelines (Cupertino widgets), and is rendered down to the individual pixel level. Flutter exploits Graphical Processing Units (GPUs) often found in newer mobile devices, further accelerating the rendering process. No Android nor iOS widgets are used in Flutter.
Every Flutter on-screen element (eg. button), layout (eg. padding, centering), or styling (eg. fonts) is a widget, including the app. As a developer you build screens by composing widgets inside other widgets, all the way up to the whole app.
Each widget is highly customisable via properties. You can also modify the Dart source code of any widget in the library as you would your own project code for further customisation.
Whilst it is possible to build screens easily with a Material or Cupertino look and feel for each platform, the Flutter documentation emphasises a brand first approach that is highly customised and largely consistent across both platforms. This maximises the single codebase approach.
The Flutter team put in a lot of effort to reproduce the look and feel of each platform’s native widgets in the Flutter widget library. For instance, navigating to the ends of a list on each platform behave differently (on Android there are visual indicators, whilst on iOS there is a bounce effect). Even the scroll fling inertia and finger resistance to scrolling is different for each platform. Flutter apps I have tried feel very natural to each platform. There is none of that slightly web browser like look and feel present on some other cross platform framework screens.
There are several benefits to Flutter implementing its own widget library. Older mobile devices can display newer widgets. Apps are less reliant on device platform version fragmentation as the widgets that you use, ship with your app. (Unused widgets are stripped from the released app). I have experienced the unwanted excitement of emergency production app releases due to OEM widgets appearing differently, or even disappearing altogether, when a new OS version update is introduced by the hardware vendor, on both platforms. This means that Flutter packaging its own widgets in the app is a real plus for me.
High performance cross platform, react inspired framework
Flutter apps are compiled down to the platforms’ native ARM machine code, which provides a high performance cross platform framework with no run time interpreter (present in some other frameworks).
During development, the Dart code is compiled using Just In Time (JIT) for fast reloading, whilst production / release code is compiled Ahead Of Time (AOT) for the fastest execution and reduced code size.
Super fast debugging with stateful hot reload
As a developer, this is my favourite feature!
In traditional native app development, you start the app connected to the IDE’s debugger, navigate down a whole series of screens, encounter a bug, try fixing it, rebuild and restart the app possibly waiting minutes, navigate down those same screens again, and find another bug a little bit further along from the previous one. Rinse and repeat this procedure all day long; each iteration taking many minutes.
With Flutter, you can truly drill down several screens, enter values on that app screen, make code changes, save the file to trigger a hot reload and in under a second, that code change is on screen, together with all previously entered values. Flutter will inform you if a full restart is required, depending on what code was changed. This makes debugging much faster, just like debugging web apps.
It can’t be overstated how much of a game changer this near instantaneous reload is (typically below one second), all whilst maintaining app state! This feature forms a large part of why developing Flutter apps is so enjoyable. This will also have a positive impact on the cost of developing apps.
Lowers barriers to mobile development
Flutter is based around the simple yet powerful concepts of composition, Stateless and StatefulWidgets to create an app. A beginner can start with a simple yet complete app consisting of a single small Dart source file. This simple starting point lowers barriers to entry for those new to mobile development. All Flutter code is written in a single language – Dart – to perform UI element declaration, layout, styling and controlling logic.
The increase in complexity is quite linear as a beginning Flutter developer learns more widgets and how to compose them. Contrast this with the complexity of the starting point for a beginning Android developer (Android manifest XML, separate activity / fragment Java, and layout XML files), or iOS developer (AppDelegate, ViewController, two storyboards); both filled with boilerplate code.
Flutter uses the Dart language in a reactive framework
Dart is very similar to Java, so the transition from native Android development using Java, to Flutter using Dart was relatively painless. With Flutter being a reactive framework, you write code to handle user and network events in a less verbose way.
Flutter code still looks very different to Android Java code because of Flutter’s use of composition to create screens. This results in deeply nested widgets that need to be managed.
In the Hot reload screen shot example above, you can see that the Text widget is nested inside the Center widget which is nested inside the Scaffold. In this simple case, there are already three nested constructors. The Scaffold also composes three separate nested heirachies of widgets (appBar, body and floatingActionButton).
For more complex screens you can see that the widgets can become deeply nested very quickly. This can be managed by refactoring parts of screens into logical sections, and creating a separate method for each section. The supported IDEs (see below) allow you to manage and easily refactor deeply nested heirarchies that make up this screen building code.
There is also less verbose, boilerplate code in Flutter as compared to native Android programming in Java, and iOS programming in Objective-C.
Clean separation of state and the building of immutable screen elements
With Android native programming, on screen elements (Views) have a dual responsibility to draw themselves on screen as well as hold state which can result in undefined and inconsistent behaviour. Examples of this less-than-ideal situation include partial restoration of the view when a device is rotated from portrait to landscape, or changing the label on a button at the wrong time or forgetting to change related button-state. With Android code, it’s common to find a fix inserted into an unexpected place to compensate for an inconsistent UI update!
Flutter has separated state from the building of immutable widgets on screen, resulting in cleaner code that doesn’t leave on screen elements in an inconsistent state.
Can access native platform features and SDKs
A typical network based app that has UIs communicating with HTTP REST APIs, or where there are already plugin libraries available, can be written entirely in Flutter. Otherwise, Flutter provides a bidirectional messaging mechanism (MethodChannel) to communicate with platform specific code, such as to read a hardware sensor such as battery level or GPS location. Each Flutter project contains Android and iOS subprojects, which allow you to continue to develop Flutter related native code in Android Studio or Xcode using subproject folders.
Supports various architectural patterns
Flutter supports the Model View Presenter (MVP) and Redux architectural patterns. Redux is supported via a plugin.
As Flutter separates state from the immutable on-screen views, the Model View ViewModel (MVVM) pattern is not a natural fit as you would have to add extra plumbing to do the data binding between the View’s separated state and the ViewModel.
Good IDE support
IntelliJ IDEA, Android Studio, and Visual Studio Code all have plugins to develop and debug Flutter Dart code. IntelliJ and Android Studio have additional debugging support to inspect view hierarchies at runtime. The Flutter SDK can also be driven directly from the command line for developers that prefer another IDE.
Substantial list of Flutter and Dart libraries available via Pub
Pub, the Dart package library, contains over 80 Flutter related packages and over 2000 Dart packages compatible with Flutter.
Good testing support
Native Android developer testing support provides unit testing (using JUnit and mocking frameworks), and on-device testing (using Espresso). Flutter testing support provides the same unit testing (using JUnit and mocking frameworks) and on-device testing (using Flutter Driver), but additionally, widget testing (using WidgetTester).
Everything on-screen is a Flutter widget, so being able to test each widget in isolation provides an extra level of Quality Assurance. You can finely control all input to the widget including gestures and taps and text entry, and verify widget state and callbacks.
Flutter builds production releases into the native Android .apk or iOS .app artifacts, so deployment of Flutter app artifacts for Test purposes (eg. into TestFlight so testers can download them) or Production (into the Android Play Store or iOS App Store) follows identical processes for native development.
What can Flutter do better?
As good as Flutter is right now, there are some issues that I think prevent Flutter from being recommended with no reservations. Here a sampling of those issues.
No support to add Flutter to an existing project
Kotlin and Swift are able to be gradually adopted into an existing project when it comes to native projects, but currently Flutter only provides templates that build brand new projects from scratch.
It is possible to manually copy the template source code into an existing project, but documentation on how to do this is hard to find at the moment.
Flutter is still in beta
The Flutter SDK is not in General Availability release 1.0 yet. Despite this Flutter apps have already been released into the Google Play Store and Apple App Store. The good thing about Flutter app releases is that they are completely self contained, in that all the Flutter library code needed by the app and runtime are included in the app binary package. This means any Flutter app in production is completely independent of future Flutter SDK releases.
There is still missing functionality between the current beta and what is expected to be in the GA release. For example, physical keyboards are not officially supported yet for Android devices. Whilst this makes development for Android a bit more of a chore as all input needs to be typed on the on-screen keyboard, this could be a showstopper if you have a requirement to support, say, Chromebooks where the majority of input is done via the physical keyboard. For a list of functionality likely to be included in the GA release of Flutter, you can check the list of outstanding issues and filter on the prod* labels. Also check the list of pub packages (see above) for any functionality you may need.
Dart is missing some language features available in Kotlin or Swift
Dart doesn’t have some handy language features / syntactic sugar available in Kotlin (eg. all the variants of when statement) and Swift (variants of switch statement) with some language features. It would be nice to switch between the languages more seamlessly.
And let’s get rid of semicolons at the end of lines whilst they’re at it!
Dart 2 is taking a step to address this by making new / const operators optional.
Flutter doesn’t have dependency injection yet
Dependency injection is widely used in native Android programming so it is important functionality that is yet to be provided. With Dart for Flutter not supporting object reflection, any solution would need to be done via code generation at compile time. Having Dependency Injection in Flutter would bring many benefits (as it already does for other platforms) to code quality, including improved maintenance and code understandability due to greater modularisation, and greater testability as it is easier to replace dependent code with test implementations.
Whilst the functional reactive style encouraged by the framework minimises the need for DI, it would still be nice to have a way of easily connecting together the various architectural layers eg. network, repository, logic, view etc. without explicit object construction so that they can be more easily unit tested in isolation. Thus there is still a valid use case for DI even in this framework.
Minimum Android and iOS platform versions supported
Flutter is only supported on Android 4.1 (Jelly Bean) for ARM devices, and iOS 8, 64 bit or newer. x86 Android devices are not supported. 32 bit iOS devices are not currently supported so this could be an issue for older iPads (eg. education market) if that is part of your target market, although there appears to be some progress on this particular issue.
Flutter’s Dart threading model is different
In Android, we must do networking and other long running operations in a separate thread, either explicitly or indirectly via Handlers, AsyncTasks etc. With Dart being single threaded and running an event loop you don’t need to create these background threads. Instead you can use async / await to accomplish the network operation. For true multi-threading (for more extensive processor work off the main thread), use Dart’s Isolates. Just be aware that this is also different to Android’s threads (eg. Isolates don’t share memory, so you need to pass messages to share information).
Accessibility functionality for Flutter is provided on a case-by-case basis, and the Flutter team encourage direct contact with them if you have needs that go beyond those currently provided. Personal experience with native implementations of customised accessibility (for a client that needed a higher level of accessibility certification) has shown that this is a very difficult area to achieve all requirements. The accessibility implementations are also very different between the native platforms. From this experience and the slow evolution of the platforms’ accessibility support over the years, the expectation here is that a Flutter implementation of custom accessibility will likely be fraught with issues as well, if you need to go beyond out of the box screen reader functionality. A Proof of Concept is highly recommended to prove or disprove each accessibility requirement.
Security tools may not be ready for Flutter and Dart yet
Some companies have policies and processes that require static code analysis to be performed over an app’s code base, identifying any potential security vulnerabilities and remediating them before they’re released into Production. Such analysis tools may not yet be ready for Dart and Flutter’s frameworks, including the Flutter runtime (consisting of Skia 2D graphics, Dart runtime and Text rendering engines). The latter three libraries are written in C++, whilst the rest is written in Dart. Everything is open source so they can be scanned, but it’s a matter of finding tools capable of doing this. If you’re considering adopting Flutter, now may be the time to engage your security analysis team in preparation.
Note that Flutter apps continue to be protected with the same permissions available to normal native apps as they all run in the same Android or iOS application sandbox environment, so data and code execution are still isolated between apps.
Continuous Integration / Continuous Delivery (CI / CD)
CI / CD has traditionally been problematic for mobile projects. Some examples of common issues include: Android emulators that run with no issues on local developer machines, but failing or crashing on the CI build machine; communications issues with Mac Mini CI build machines for iOS resulting in repository access errors or inability to access stub servers when running tests, and so on. With Flutter projects having one main source code repository but two native deployments, time and effort needs to be made to shake out the new build targets for each platform, invoked via flutter build rather than the traditional gradle or xcodebuild for native projects. Unit and widget tests in the CI build are invoked via flutter test and for on-device tests, flutter drive.
Flutter is the most promising cross platform mobile development framework that will appeal to native mobile developers, and likely other developers too.
Headed up by a team of ex-Chrome developers at Google (so they know rendering), it delivers on great UX for end users with its performant rendering and runtime architecture, native look and feel, and high customisability, perfect for a brand first approach.
It delivers for developers with super fast debugging using stateful hot reload, easy to learn Dart language and simpler reactive style coding.
I would recommend considering Flutter for your next app taking into account the user requirements.
At the very least, give Flutter a try and checkout the sample apps, particularly the Gallery app.
I’m glad I did!
Get started with Flutter including introduction and FAQs: https://flutter.io/
Flutter Framework link: https://flutter.io/widgets-intro/
Dart language link: https://www.dartlang.org/
Blog on why Flutter is different: https://hackernoon.com/whats-revolutionary-about-flutter-946915b09514
10 minute video: What is Flutter:
30 minute more in-depth intro to Flutter:
Flutter Gallery in Google Play store link: https://play.google.com/store/apps/details?id=io.flutter.gallery&hl=en
Flutter Gallery source (iOS version needs to be built from source): https://github.com/flutter/flutter/tree/master/examples/flutter_gallery
Dart Conference Jan 2018 presentation playlist, many discussing Flutter: https://www.youtube.com/playlist?list=PLOU2XLYxmsIIJr3vjxggY7yGcGO7i9BK5
Flutter presentation at Google I/O 2017:
Links for Hamilton app written in Flutter by an agency in three months and promoted by the Flutter team:
Google Play Store: https://play.google.com/store/apps/details?id=com.hamilton.app&hl=en
Upcoming Google I/O 2018 schedule link with 11 presentations relating to Flutter: https://events.google.com/io/schedule
Future Dart language features being considered: https://www.dartlang.org/faq#q-can-dart-add-tuples-pattern-matching-non-nullable-types-partial-evaluation-optional-semicolons-