I’m a front-end developer who has worked mostly with Angular as well as basic html/ javascript. As a company we focus on the early phases of app development. We help companies go from idea to app and assist them with the choices that start-ups face. This post will tell something about my experience with building our company’s first Flutter app. Hopefully this will help if you consider Flutter for a future project. It’s preferable if you already know a little about Flutter and programming in general as I won’t go into detail about what Flutter is. Even so there might still be some terms that you might not know about. I’ve tried to add some links for extra background information, but don’t hesitate to ask if anything is unclear.
Standing still and blindly sticking to a certain framework might seem convenient as programming will get more efficient and estimating development time more reliable. But in such a fast moving world it is also risky, not knowing what other and maybe better solutions are out there, otherwise all programmers would still be punching holes in paper.
We used the Ionic framework for all of our previous apps. Although we are fans of Angular and Typescript, we experienced some performance issues and problems with Cordova. Another problem with running an app in webviews, is the fact that the css can be interpreted differently, and especially the iOS webview created some annoying css issues. Switching to native is not an option for us, as we mainly target startups with an idea for a new app and limited budget. We would like to bring these ideas to as many people as possible without the larger budgets involved with creating and maintaining 2 separate native apps. We recently started a new project: Astmakompas. This app tries to help asthma patients improve their quality of life by enabling their caregivers to monitor remotely, and giving the patients insights regarding their condition. This gave us the opportunity to try out a new framework.
We were eyeing React Native for a while as an alternative to Ionic, as it was expected to fix some of the performance issues we were experiencing with Ionic, and in general seemed to have become the go-to cross-platform framework. But Flutter brought another exciting option. We chose to try Flutter as it seemed to be the bigger innovation. Flutter compiles to native code (no JavaScript layer like with React Native) and thus promises even better performance. If we found out it wasn’t a good fit, we could always switch to React Native or fall back on Ionic.
Starting a project is extremely simple, the default app is a counter app where all widgets are in the same file. This app can be used to try some simple layout options and very basic state management. You can also immediately see the benefit of hot reload. With Ionic, changes in the code are visible after a few seconds, faster than a full rebuild, but way slower than the instant changes possible with Flutter hot reload. They even added animations for some of these changes, like font size and color in Flutter! The Flutter documentations is good, although I would’ve appreciated some examples of more complicated features. The beginner tutorials are great to try out Flutter, but I don’t feel they cover any of the more difficult concepts to grasp, so they can easily be skipped.
Flutter now has an awesome experimental tool, with which you can mess around in your browser with Flutter for web: DartPad.
Dart was relatively easy to start with. I used Dart Academy Bootcamp to get introduced to some of the basic concepts and quickly felt comfortable to start programming with it. Coming from TypeScript I found some similarities and some differences. In general I feel TypeScript is richer in features and more flexible/forgiving. Debugging typescript felt quite a bit easier as well, since finding out where some error actually originated has been hard in Dart sometimes, although that could also have to do with Flutter vs Angular. Dart seems very robust and the fact that it’s so strictly typed, means that IntelliSense works very well. Even with all the external libraries. With typescript you sometimes run into external libraries that are plain javascript or not fully typed, which means it’s a lot harder to see what methods are available and what the expected function parameters are. The strict and basic nature of this programming does prevent a lot of mistakes and forces you to think very clearly about your code, so overall I’m satisfied with Dart.
Flutter is an app framework that can be used for multiple platforms, for now I’ll only go into iOS and Android, but there’s a beta out for web as well and more platforms are coming. Flutter is written in Dart, which is compiled to native code when building an app. No WebView is used (like in Ionic) and no native UI elements are used (like in React Native). Instead Flutter draws all UI pixel by pixel and when you want to use a platform specific button for example, you can use a Flutter widget that looks like a native element.
Flutter apps consist of widgets, these are used for almost everything, and you can define your own widgets as well. Coming from html/css, all styling and layout is done by setting specific properties of widgets or nesting widgets in another widget that was meant for this specific purpose. Global styling can be set with a Theme widget. We’ll be skipping over some steps here. I won’t go into detail about many of the core elements that shape a Flutter app, such as widgets and themes. Instead I’ll focus on state management, build environments and some random stuff that caught my eye. I feel that state management and a streamlined build flow are essential for a successful production project, and the random stuff will spice things up!
Our app includes user accounts, chat functionality, graphs, push notifications and quite some requests to our back-end server. So instead of doing a tutorial and learning how to build a todo list, I dove straight into state-management. I feel you only run into limitations of a framework when you start adding more advanced features. I’m sure the default Flutter counter app works just as well as a jQuery PhoneGap app, but start adding features and you’ll wonder why you decided to build your car frame using recycled toothpicks instead of steel. It seems easy to start, but things start falling apart soon enough. Starting out with implementing complex state management seemed like a good test to see if a Flutter app would fall apart or not. This is also where we made the first mistake. Most of our apps use NgRx, an awesome state management library for Angular inspired by Redux.
This solution has quite some (sometimes frustrating) boilerplate but is also very structured, powerful and feature rich. I set out to implement the Flutter Redux counterpart but soon found out that it was quite limited in features compared to what we were used to. I then found out that the involved github projects didn’t seem to be active anymore. We had to switch, and chose BLoC. It took a while to figure BLoC out and there seemed to be different opinions on how to correctly implement it, but thanks to all the content out there we managed to get it running. As I’m writing this blog a big update for the flutter_bloc package came out so there’s plenty of features being added, which gives me confidence we chose the right tool!
Check it out: flutter_bloc.
Once we managed to tackle complex issues like state management and build environment, we felt confident that Flutter was ready to be used in a production application
Keys are useful references to access a certain widget. But keys can also be useful when for example a list of stateful widgets gets reordered. Without keys, the state doesn’t automatically get reordered as well. I ran into an issue like this with the SliverList widget in combination with dynamic content combing from a BLoC. I find the lifecycle of widgets in Flutter slightly confusing. The build function of a widget gets called multiple times, so don’t use this for executing functions that only need to be called once, unless you have a way to check if they’ve been called already. You can use InitState, but this can create some issues when you need to use the BuildContext. DidChangeDependencies gives full access to the BuildContext, but it can be called again if you’re using InheritedWidget . I ended up using the build function and a boolean to track whether the build function has been executed before.
Keys are useful references to access a certain widget. But keys can also be useful when for example a list of stateful widgets gets reordered. Without keys, the state doesn’t automatically get reordered as well. I ran into an issue like this with the SliverList widget in combination with dynamic content combing from a BLoC. I find the lifecycle of widgets in Flutter slightly confusing. The build function of a widget gets called multiple times, so don’t use this for executing functions that only need to be called once, unless you have a way to check if they’ve been called already. You can use InitState, but this can create some issues when you need to use the BuildContext. DidChangeDependencies gives full access to the BuildContext, but it can be called again if you’re using InheritedWidget . I ended up using the build function and a boolean to track whether the build function has been executed before.
Here are some things I feel could be improved in either Dart or Flutter.
So what’s the status after 3 months? My colleagues are obviously jealous that they’re still not working on a Flutter project and I try not to rub it in when they curse about some Cordova plugin dependency issue. We’ll start a closed beta soon and the creation of our first Flutter app has been a great experience so far. The app looks and feels exactly the same across all devices. It also feels quite snappy compared to an Ionic app, especially on older devices. Just start playing with Flutter and tell me what you think!