developing the MapChart mobile app with Flutter
A few of my thoughts and notes on using Flutter as the framework for MapChart's iOS and Android app.

As I said in a previous post, Flutter was my choice for creating an almost identical clone of the website into an iOS and Android app.

The promo video for MapChart’s mobile app.

This post lists some advantages and drawbacks I stumbled upon while developing the app. It is not meant to be a full-fledged review of Flutter; some of these are pretty random.

It is targeted mainly to fellow developers, that may consider using Flutter for their projects.

Indeed, being mainly a web developer, my experience with mobile app development was fairly limited.

MapChart is the only app I have ever published on iOS and Android. Apart from that, I had only done some simple courses before in Android dev with Java, but nothing concrete.

Altogether, it has been mostly a pleasant experience, especially if you consider my background.

I was able to learn the Dart language and Flutter pretty fast and have the app published in both app stores in less than two months time.

Matter of fact, I:

  • First started learning Dart and working with Flutter in the first days of October 2020.
  • Made the first commit to the app’s repo on October 21st.
  • Published both apps (iOS and Android) on December 3rd.
first commit to mapchart's repo
The first commit to the app’s repo was on October 21st, while the app went live less than two months later!

What is Flutter?

Flutter is Google’s UI framework for developing natively compiled apps for iOS and Android (and recently the web, Windows, and macOS as well) with a single codebase. It has grown really fast the past few years and recently reached the version 2 milestone.

I wanted to avoid learning two different ecosystems (Android and iOS) and languages (Java/Kotlin and Swift) to build the app for both mobile platforms. For this reason, it only made sense to use a cross-platform approach with a single codebase, such as the one Flutter offers.

Before, I had done some tutorials and experiments with React Native, but I fell it came short to its promises. Flutter offered a whole different development experience and quality, which I analyze more below.

What I loved

The widget system

It’s really easy to get a beautiful app up and running with Flutter’s widgets.

Everything I needed for MapChart’s UI, like buttons, checkboxes, menus, navigation, icons, etc., were already available and easily customizable within the framework.

Widgets also look identical between iOS and Android versions, so you don’t have to micromanage the different platforms.

Flutter allows you to easily build nice UIs, using the industry-standard Material Design guidelines.

In most cases, I just had to declare how the widget tree should be constructed, and got by default a great UI result. Styling the different components is intuitive and pushes you to adhere to Material Design guidelines.

In general, I quickly went from a sketch, to a wireframe, to adding more complex components to the UI step-by-step:

Of course, a lot can also be said for Flutter’s declarative style and rebuild trigger. State management is a major theme for Flutter, but I managed to get by, for the time being, with using just the default setState({ }) pattern, instead of a more advanced solution.

Dart is a great language

I truly believe that Dart is Flutter’s ultimate weapon. It’s a programming language with a familiar syntax, that falls somewhere between Java/C# and JavaScript/TypeScript. In fact, Dart also compiles to JS, as Google initially intended to use Dart in Chrome’s VM.

Dart is easy to get started with. Reading the language samples and doing all available codelabs can get you in the right direction. Most video courses you can find for Dart also involve Flutter, with more springing up each month. Even though I didn’t get through all of its material, I would highly suggest Code with Andrea‘s Flutter courses.

Since Dart is a statically typed language, you also get the benefits of static checking and a sound (and now null-safe!) type system. Dart’s Analysis tool is integrated into any IDE and performs code analysis and hinting really well.

Due to the above, some of MapChart’s web version code was almost directly “translated” from JavaScript to Dart. Check for example the below shortened snippets, covering the process of saving the map’s settings:

In JavaScript (web version):

function saveConfig(autosave = false) {
    let toEncode = {};
    toEncode["groups"] = {};
    for (let colorHex in colorsData) {
        let divName = colorsData[colorHex].div;
        let divNumber = divName.match(/\d/g);
        divNumber = divNumber.join("");
        toEncode.groups[colorHex] = {
            "div": divNumber,
            "label": colorsData[colorHex]["label"],
            "paths": colorsData[colorHex]["paths"]
    toEncode["title"] = $('#map-title').val();
    toEncode["hidden"] = hidden;
    toEncode["background"] = $('#backgroundpicker').spectrum("get").toString();
    if ($('#show-usa-states').length) { toEncode["usaStatesShown"] = $('#show-usa-states').is(':checked'); }
    if ($('#show-canada-states').length) { toEncode["canadaStatesShown"] = $('#show-canada-states').is(':checked'); }
    if ($('#split-uk').length) { toEncode["splitUK"] = $('#split-uk').is(':checked'); }
    return JSON.stringify(toEncode);

In Dart (mobile app version):

Future<String> _saveConfig([bool isAutoSave = false]) async {
  Map<String, dynamic> toEncode = Map<String, dynamic>();
  toEncode["groups"] = {};
  int n = 0;
  for (Color color in _colorsData.keys.toList()) {
    String colorHex = colorToHex(color);
    toEncode["groups"][colorHex] = {
      "div": "#box" + n.toString(),
      "label": _colorsData[color]["label"],
      "paths": _colorsData[color]["paths"]
  toEncode["title"] = _legendTitle;
  toEncode["hidden"] = _hidden;
  toEncode["background"] = colorToHex(_currentBackgroundColor);
  if (_usaStatesShown) toEncode["usaStatesShown"] = true;
  if (_canadaStatesShown) toEncode["canadaStatesShown"] = true;
  if (_splitUK) toEncode["splitUK"] = true;
  return jsonEncode(toEncode);

By all means, porting code like this sped up the whole process. It also ensured that the same behavior and functionality is found in both versions of MapChart. For my specific use-case, I had to spend some time with the integration of the SVG maps, but it wasn’t difficult to set up a custom parser to do the job.

Using Android Studio as my IDE of choice

The two most popular IDEs for Flutter development seem to be Android Studio (IntelliJ) and VSCode. My choice was to use Android Studio for the whole development process on my Windows laptop, and VSCode with XCode on my cloud Mac computer (more on that later).

Android Studio works great. It runs fast, has many shortcuts and settings to customize, and the Flutter and Dart plugins integrate seamlessly. As I primarily use Sublime Text 3 for web development, it was also a huge productivity boost to be able to change Android Studio’s keyboard shortcuts to Sublime Text’s shortcuts, with just one setting!

Setting Android Studio to use Sublime Text’s keyboard shortcuts.

Flutter’s Hot Reload is outstanding

By far my favorite among Flutter’s development features. You hit Ctrl+S on Android Studio and you immediately see the effects of your changes on the app.

On one of my short brushes with React Native, Expo’s live reloading was the bane of my existence. There were countless times when the app wouldn’t reload, and I had to restart, or reconnect and rebuild the app from the start to get it working.

Flutter’s Hot Reload never failed me once during developing the MapChart mobile app. It just works.

On the same note, the other development tools, like the performance profiling, the widget inspector, and the various command line tools, proved useful as well. I must admit that Flutter’s team has really raised the bar here for any other current mobile app framework.

What I didn’t like

Issue with performance in the Android version 🐘

Update! The issue has been fixed in version 2 of the app! Although the underlying issue with Flutter hasn’t been fixed yet, I found a workaround to get better overall performance.

And now we come to the elephant in the room!

There is a big difference in the app’s performance between the iOS and Android versions, especially when zooming or moving the map around.

While the app runs on high FPS rates on iOS devices and high-end Android ones, the rest of the Android devices get a big performance hit.

Lag appears when trying to zoom in and move around on some maps in the Android version.

This issue is of course more apparent when someone uses the larger maps, like the US counties or the World subdivisions maps. Obviously, it has also been the main complaint coming from Android users, who find it cumbersome to use the app in this state.

Unfortunately, there is no solution for this yet. I have tried to tackle this with various techniques and performance optimizations, but it seems to be an issue with Flutter’s underlying painting framework.

There are other developers that have encountered this problem with their apps. Already, there are many open issues on Flutter’s GitHub tracker that await a resolution (mine, and a couple other similar issues). So, for the time being, we can only wait for Flutter’s team to address such performance issues.

Package support for Flutter has some issues

As is usually the case with plugin ecosystems, there are 3 main categories of third-party packages on

  1. High-quality packages that are also well-maintained
  2. High-quality packages that haven’t been updated for a while
  3. Low-quality packages

Of course, the #1 and #3 categories are expected to exist; it is the 2nd category of packages that create the most problems. It is really frustrating to find that one of the most important dependencies for your app has been largely abandoned, forcing you to find an alternative and refactor the whole codebase.

The color picker comes from a package available on

A general rule I would suggest everyone to follow: when choosing a package to use, have a look at its GitHub issues first. It is a great measure of how well and frequently its maintained, and you can make sure that there are no unsolved issues for features you may need for your app.

Furthermore, support for official plugins from Flutter’s team (like maps, Bluetooth, Firebase, etc.) has been notoriously flaky. However, this seems to have improved in the past months.

Poor support for SVG

Flutter has a fairly limited support for using SVG files, like MapChart’s maps. As I said previously, I had to write my own SVG parser to render them as a Flutter widget.

Handling events or other usual SVG interactions requires using third-party packages, which in turn, need to be modified for the specific use-case. Again, this is a better situation, as I have seen, compared to similar frameworks like React Native or Xamarin.

The Apple Developer program needs some changes

This is not an issue with Flutter per se, but with Apple’s build, review, and publish processes for App Store apps:

  • You need an Apple Developer account to be able to publish apps to the App Store. After signing up and paying the required fee of $99/year, I had to wait almost two weeks before being accepted to the program, and only after speaking with Apple’s support, who requested additional verification steps.
  • You must have access to an Apple device to be able to sign and build the app. Since I didn’t have one at the time, I had to rent a Mac in the cloud (from macincloud). Not a major issue, since using GitHub to move code from one machine to another was easy, but still, an additional requirement to manage.
Developing on a cloud-based Mac with VS Code and Simulator.
Developing on a cloud-based Mac with VS Code and Simulator.

App Store Connect and its pitfalls

App Store Connect, the platform that iOS and Mac developers use to publish and manage their apps, seems a bit neglected compared to other Apple products.

Its design seems to be all over the place and patched together from different UIs, something unusual for Apple’s standards.

Moreover, there are multiple agreements and statements to fill out before getting verified and being able to publish your first app, with each one having its pitfalls.

My favorite moment was when I was asked to input my tax info. After filling in the address field, hitting submit yielded an obscure error message. I tried various form of my address, like using all caps, omitting the number, putting the number in front, etc., but still got the same error.

In the end, and right before having a mental breakdown, I found a solution in the Apple Developer forums: I needed to hit the button 3 times for some unknown, magical reason! Why the hell couldn’t I think that I could brute-force this? This hideous bug in that form has yet to be fixed, as far as I can see 😑.

The solution for the “Address is invalid” error while filling one of App Store Connect forms.

Ultimately, Google’s Play Console was really easier and more intuitive to use. It has all features, forms, and controls that you may need for app development and monitoring, in the familiar dashboard interface from other Google products.


Despite the above issues, I truly believe that Flutter was the best choice for developing the mobile app for MapChart.

It provided me with a great environment to work in and have a mobile app ready for both iOS and Android in almost two months time, without prior experience!

From the website to a mobile app with Flutter!

In the next few years, my feeling is that Flutter will come to dominate the cross-platform mobile framework market, so if you are thinking of getting a head start, now it’s the time to do so.

I hope you found this post informative, though it was more on the technical side. More updates and maps are coming both to the website and mobile app, so please stay tuned!