Last year, we researched the Flutter framework – and heavily, for that matter.
New technology from Google looked very promising. It provided a new approach for cross-platform-development.
Welcome to a whole new take on a Flutter Success Story. This one comes straight from an Android Developer’s Perspective.
Reasons for Using Flutter
Our Android team had mixed feelings. As the native Android ecosystem matured, we could finally use modern language (Kotlin), universal architecture, and clarified library sets.
On the other hand, many customers could not agree with our need for performance, and insistence on animation smoothness when discussing the application budget.
The fact is, it is simply too expensive for most customers to own a native app, particularly if it’s not a core part of the business. Cross-platform apps were hot topics, and demand for React Native developers skyrocketed.
Once we felt comfortable with the new framework, an opportunity appeared. As new projects arose, we established:
- Custom styling (far from default Material or Cupertino) for both platforms. This is needed as the App must look identical on both platforms
- It’s a “fat client” app – API is quite raw, with much on-device processing necessary
- A desire to write the business logic, as maintaining the same algorithms in both Kotlin and Swift is hellish.
Throughout our research, we noticed the Redux/Bloc pattern felt natural in Flutter. It’s quite a functional language, complete with stream support. At first, we relied on our implementation of Bloc but quickly switched to the felangel Bloc library. We were surprised by the lack of a default dependency injection system. We looked for a Koin clone for Flutter, but eventually, Provider worked well. We didn’t need to use sophisticated architecture.
For reference, see the simplified diagram.
That part of development is my personal favourite. I have an Android background, and I’m used to building activities, fragments, and custom widgets by declaring xml. Even though Android tooling improved, I still found it time-consuming. Styling, theming, and using standard widgets requires a great deal of boilerplate code. Flutter’s declarative UI initially makes you wonder what’s going on. But once you get it, you won’t want to go back.
Flutter community is, interestingly, quite novel. Hence, at the moment of implementation, we could not find general guidelines, so we created our own:
- We prefer immutable constants over variables (final FTW), as well as immutable classes
- For each Bloc, we created an abstract class for the base event and state, to extend for concrete use cases
- Bloc listeners are the way to handle dialogues and navigation changes
- Blocs can yield new states when handling events from the UI.
The Internet is full of Flutter praise and excitement. The project’s release had finished successfully, and we generally enjoyed our time spent coding. However, I’d like to share a few words of bitterness. Some aspects managed to confuse us, and even provoke an anger episode, or two.
Dart – Kotlin’s Less-Charismatic Counterpart
It’s hard to say that programming languages are related. But for developers knowing Kotlin and Dart, the second one resembles Superman’s evil cousin. The luxury of skipping the use of colons had spoiled us. But the way Kotlin handles nullability was a game-changer in the programming world. We missed the nullable typing system and were also surprised by the way Dart guards types safety.
It’s a common case when you want to show a dynamic list of widgets mapped from their state. A simple map operation should be enough, right? After all, code is compiling. But once you passed your collection to Column, as a child could do – error – we are expecting Lists, not Iterables. We encountered many such cases, where types match in compile time but crashed on runtime. Bummer.
The Dartfm tool worked strangely – we even synchronised project settings. Throughout the review, we lost incredible amounts of time by looking at just formatting changes.
Invading iOS’ Territory
Let me confess first; I started this project as an Android Developer with little knowledge of the iOS ecosystem. I knew some basics and wanted to learn more by doing. It’s not Flutter’s fault, but the iOS app environment feels hostile for unprepared wanderers. Luckily, we could ask for help from our experienced iOS team. Thanks to their colossal effort in explaining, we were able to manage certificates, import native libraries, handle ad-hoc and store distribution. But if you’re an independent developer, I strongly suggest these steps:
- Take a look at the superb CS193p course from Stanford – available online and read the official Flutter guide for iOS Developers
- In our case, we also struggled with 3rd party libraries that worked fine on Android but caused the iPhone screen to bleed – especially WebView.
Choosing Flutter for Your Project
Despite all my complaints, I find Flutter attractive for mobile developers. It brings a breath of fresh air, and offers a fun perspective, making app development enjoyable again. But we can’t judge technology only by a programmer’s feelings.
After all, it’s a summary of end-user experience, development cost and maintainability, overall stability and performance. And here, Flutter nailed it. Our customers loved it. The result had been nearly 100% crash-free, smooth and responsive.
When choosing technology for this project, I made a big risk, betting on young technology. But I think Flutter paid off. Next time, when analysing similar projects, I would pick Google framework again. And If I could make a wish now, I’d ask for Kotlin support in the future.
Build cross-platform mobile applications with Flutter