Jun 13, 2019

Our Journey with Flutter

Michal Ursiny
Michal Ursiny
Our Journey with Flutter

Flutter, a relatively new cross-platform framework backed by Google, has become very popular over the last 18 months.

A Quick look at the steep rise of Stack Overflow questions demonstrates how quickly Flutter has risen to prominence as a cross-platform development solution - reaching React Native levels of popularity in a much shorter timeframe.

% of Stackoverflow questions that month

Last year we evaluated React Native. Check “To React Native or to Not React Native, That is the Question” for more details.

On its face, Flutter has a very attractive proposition:

  • One codebase, multiple targets:
  • It’s fast. Flutter uses its own rendering engine, Skia, and it’s capable of providing a fluid 60 FPS user experience - which can get up to 120 FPS for some devices. High refresh rate is especially noticeable during animations.
  • Rapid development. Hot reload is just awesome - you just hit “Save” and it’s there. It works most of the time during the standard development loop. Occasionally, it will force you to do full rebuild, e.g when you change dependencies, and it’s perfect for polishing UI.
  • Clear UI updates. Unidirectional data flow architecture prevents you from messing with the view hierarchy any other way than through build method.
  • Backed by Google. A major player (obviously) that seems to be investing a lot of resources into it. So, it’s a pretty safe bet.
  • Easily extendable with first/third party packages from https://pub.dev/flutter

Our target: Proof-of-concept app

Our goal was to create a proof-of-concept project that would mimic our mobile apps. We wanted to see whether Flutter could enable us to deliver a basic catalogue browsing app with the ability to play content.

Main navigation flow through the app built during the workshop.

It took us about a week (a remarkably short time) to learn and deliver a concept app for browsing the most popular content from our catalogue, displaying detail, and playing the trailer where available.

Challenge 1: Dart - don’t worry about that

The first challenge we faced was language - Flutter uses Dart. Our worries, however, were unsubstantiated. Dart is a mature language, released in 2013 and currently in version 2.3.0, so it’s been through enough iterations to be dependable. It’s open source and backed by Google, which helps. We found it easy to pick up, and, for Android developers among us (like me), it seemed like something between Java (welcome back semicolon!) and Kotlin. On the other side, iOS developers found it a bit more difficult to adapt from Swift.

A few notable differences include:

Declaring variables / constants

Implicitly var someInt = 5;var someInt = 5var someInt = 5
Explicitly String name = 'Stan'; var name: String = "Stan"var name: String = "Stan"
Dynamic type dynamic name = 'Stan'; var name: dynamic = "Stan" Not available
Constants final name = 'Stan'; const name = 'Stan'; val name = "Stan" let name = "Stan"

Nullability / Optionals

Declaration int id = null; id.abs(); // Exception id?.abs(); // Safe var id: Int? = null id.inc(); //Compile error id!!.inc(); // Exception id?.inc(); // Safe var id: Int? = nil id.signum(); //Compile error id!.signum(); // Exception id?.signum(); // Safe
Nil coalescing operator / Elvis operator int id = null; int else = id ?? -1; var id: Int? = null var else: Int = id ?: -1 var id: Int? = nil var else: Int = id ?? -1

Classes, protocols, and inheritance

Inheritance class Dog extends Mammal { }class Dog: Mammal { }class Dog: Mammal { }
Data class / Struct Not available data class A(var a:Int) { } struct A { }
Protocol / Interface Not available interface Countable { fun count(): Int } protocol Countable { func count() -> Int }

If you are interested in these, please see our workshop presentation dealing with Dart specifics.

Challenge 2: Architecture

Flutter doesn’t really guide you on the architecture of your app. However, you DO WANT architecture so you won’t end up with unmaintainable mess, and you DO WANT to have your business logic elsewhere, and keep the layout as dumb as possible. In the end, we settled on every screen having its own ViewModel, where all the business logic is happening and communicating with the UI via Streams, which we have found to be ideal for updating the UI when data is loaded from the API in a reactive way. You just subscribe to the stream from the ViewModel and update the UI accordingly to the state of the stream and data passing through that pipeline:

   stream: _viewModel.items,
   builder: (
     BuildContext context,
     AsyncSnapshot<List<HomeItem>> snapshot) {
     if (snapshot.hasError) {
       return _error(snapshot.error);

     switch (snapshot.connectionState) {
       case ConnectionState.none:
       case ConnectionState.waiting:
         return _waiting();
       case ConnectionState.active:
       case ConnectionState.done:
         return _loaded(snapshot.data);

Again, check out our workshop presentation and repository for more details.

When you hit the wall

Not everything is green in the land of Flutter. When you need something special - or, as one of our workshop attendees said, “When you hit the wall” - you’re stuck and you won’t find as much help on Stack Overflow as you are used to when developing native Android / iOS apps. While the rise of Flutter has been phenomenal, it’s still a far cry from the land of native development.

The first thing is to look at https://pub.dev/flutter and see if the thing you need is already available. This is exactly what we did when we were searching for a movie player solution. There’s a nice package called video_player maintained by the Flutter team itself, and a UI wrapper chewie, which works as a drop-in video player solution.

However, that’s exactly where we hit the wall. The layer wasn’t playing our videos on Android. Our investigation revealed the issue to be that video_player was not detecting DataSource content type, as video_player was looking for certain .ext in the URL path to detect it. The only way around it was to fork video_player and do some modifications that let us directly tell and override video_player detection of DataSource. Subsequently, we forked chewie to use our video_player mod. Of Course this puts an extra burden on us to maintain a separate library - which is not an ideal situation.

If your business lies in the land of native, like a movie player or map, then be ready to face such issues. Flutter gives you the tools to do things on the native side, but that diminishes what is likely the main reason you would adopt Flutter in the first place.

Sharing is caring

We decided to share our experience with the community via a workshop at the mDevCamp 2019 conference for mobile developers.

During our proof-of-concept phase, we had an overly-positive experience. The main thing was the rapid development and adaptation. We were able to deliver proof-of-concept in very short timeframe and the app quality was smooth and responsive – and with both iOS and Android covered!

We were excited and we wanted attendees to experience the same, so we divided the workshop into 5 steps, subtitled “from zero to hero”:

  1. Build grid UI (stateless)
  2. Build grid UI (stateful)
  3. Load data from API
  4. Build Detail and navigate to it
  5. Build Player

Every step addresses a typical task you encounter while building an app. You need to build UI, prepare your data layer and load data from the API, handle navigation, and (of course) display content – in our case, play a movie trailer.

Support material for the workshop is available at https://github.com/Showmax/flutter-workshop. You can access presentation directly via https://github.com/Showmax/flutter-workshop/blob/master/presentation.pdf. We encourage you to clone it and try to go through the workshop yourself. While there is still room for improvement, feedback received so far is quite positive. Hope, it will be helpful for you as well.

Big thanks to our workshop attendees for making our workshop a success!


While we find Flutter exciting, we haven’t decided to go that way - for now - for several reasons:

  • No tvOS support - which is a big deal for us
  • Because of our experience with video_player, we feel like it’s not mature enough and we’d still need to maintain your own native-side code
  • While the documentation is good, there’s not enough support when you hit the wall - you won’t find that much support on Stackoverflow compared to native development

These cons will probably be eradicated in the very near future and we may see ourselves jumping on the bandwagon. We want to be ready. But not for now, we will keep an eye on this exciting development.

Share article via: