Game engines have been doing this for a very long time. Every game engine has their UI rendering library which enables the game developer to compose UI with their own branding, style, and interaction on all platforms. Games do not even adhere to the “UI Guidelines” because they need to stand out.

Applications nowadays tend to design around the brand and not the platform. If people already familiar with the app in one platform, they expect it to behave the same in another platform. Brand consistency is important. This is what we want to aim for.

Flutter also handles its own animation and gestures. This gives Flutter total freedom on how UI widgets are composed and how a user interacts with them in a similar fashion. Flutter enables us to write our UI based on our brand. The way Flutter was made is a match for our requirements.

It turns out we spent a helluva lot of time building and tweaking the UI before even integrating to the backend. There’s always that “something” that needed to be adjusted fast. Flutter supports hot reload during debug building. Which mean developers can just adjust and run and see the result. This makes us able to iterate the UI for both platforms really quick. On release mode, flutter will spit out the AOT compiled code.

Consistent Way of Communication With The Backend

Our backend was written in Go and it exposes a RESTful API. To make it work effectively, we created the SDK to access to the server endpoints seamlessly. If we were to implement those in Android and iOS separately, we would need to create two different libraries as they do HTTP and JSON marshalling and unmarshalling differently.

Thanks to Dart’s HTTP package, built_value, and built_collection, we’re able to write an asynchronous client SDK with immutable data structure. This SDK is used by both Android and iOS app and also WebApp because later on, we decided to write our dashboard using Angular Dart to be able to further leverage our shared Dart SDK.

Just recently, the dart team even announced gRPC support for Dart. This is amazing as this will enable better integration as we’re planning to use gRPC on our services in the near future.

A Statically Typed Language

We have a strong opinion on using statically typed language whenever possible. We like to express something in terms of its type. This is the reason we decided not to use React Native in the first place.

Dart is not perfect, but it has things that we need: a statically typed language with the combination of compile-time type checking and runtime time type checking. It has a built-in mechanism for asynchronous using future and async-await . It helps tremendously in handling event and network packet.

Dart is similar to Java. Our API SDK for Dart is written by our backend engineer. We don’t really separate engineers by layers, and having a language like Dart enables our backend engineer can create one SDK for all three platforms in pure Dart. The language is easy to grasp, and it saved us a tremendous amount of time.

But Flutter Also Make Us Suffer

While Flutter saved our investment in time and money. It was also a risk. This tweet showed my frustration when helping the team working on Amazon Cognito.

My frustation with Flutter

Possible Bug in Dart Standard Library

Edit: This is already Fixed.

We didn’t use the stable channel at that time because the changes from Dart 1 to Dart 2 is major and we do need features from Dart 2. There was one particular bug that irritated me so much is the modpow(x^y mod N) bug on dart dev channel before version 0.54. Amazon Cognito is utilising SRP and RSA for authenticating and verifying the token, and I need BigInt with correct modpow implementation. I scavenged code from other people. Thankfully, Google has dart code handling simple RSA. I looked at them and learned that my code was correct, but Dart implementation was buggy.

Documentation Scarcity

Edit: This is improving, but still lacks.

When I first used libraries create by Google itself like built_value and built_collections , the docs was nearly zilch. On many occasions, I needed to peek in the source code on GitHub to know what’s going on and how to use it. Thankfully, Google’s standard of publishing source code has plenty of examples in it.

Need To Build Things Yourself

At the time I wrote the app, there was no Amazon Cognito SDK for Dart, so I needed to follow their documentation, test them out using raw curl , peek the source code written in other languages, and reimplement it in Dart.

We can’t rely on the availability of the libraries written for Dart. Cognito is one example. For me, this is fun part. But for other people, this can be a no-go. The amount of nights and coffee I spent to figure out how these things work in Dart is paid off as once I can figure them up. It can be used on all three platforms with very minimal changes.

Conclusion

Working with bleeding edge technologies comes with risks, but the risk of using Flutter and Dart is worth the investment. The fact that we used the dev channel just make us feel like we are working together with Google’s Flutter and Dart team and always keeping track of the issues.

We managed to build our first prototype in 3 weeks with a single client developer and a single backend developer. This is impossible to do if we write them in their own respective IDE and language.

If you wonder what kind of app we’re making, our CEO will announce it in the coming months when our products is ready. So stay tuned.