This collection of posts will share my journey of creating the same mobile game app using three different UI toolkits:

  • Flutter, a cross-platform UI toolkit that uses Dart as its programming language, from Google.
  • Jetpack Compose, Android’s modern recommended native solution for building UI, using Kotlin.
  • SwiftUI, Apple’s most recent declarative toolkit, using Swift.

Please note: this is not meant to be an exhaustive comparison and analysis of the three toolkits. I will merely detail my own experience, coming from my specific background, so take everything with a grain of salt.

This also means that I won’t be declaring a winner in the end. You are welcome to choose and go with what best fits your unique needs.

Motivation

I feel that we have reached the point where all three of the above declarative UI toolkits are mature enough to use in production apps.

Both Google (for Flutter and Compose) and Apple (for SwiftUI) are motivating developers to use these new toolkits.

With numerous similarities in how they handle declarative UI, this exploration now makes sense.

Crucially, in 2023, each toolkit boasts a vibrant community, replete with an array of tutorials, StackOverflow responses, and instructional guides. Additionally, AI systems like ChatGPT, having undergone extensive training on this content, are adept at offering precise answers and solutions.

The app

The app I am building with the three toolkits is MapGame.

It’s a fairly simple geography trivia game, that was first published as a browser-based game in September 2023.

The gameplay is straightforward:

  • You get a map that you can zoom in/out and move around.
  • Every day, there is a different hidden country.
  • You get a hint, like “The country is west from Vietnam” or “It has red in its flag”, and try to guess the hidden country.
  • Every guess you make, you unlock another hint. You have 10 lives.
  • In the end. you get points, depending on if you found the country, your time, and how accurate your guesses were.

Try playing one round of MapGame in the web version. It will be enough to get the gist of it.

The game also features a Practice mode with unlimited play, stats and game history tracking, and a share component, so you can challenge your friends and family.

I think it’s an excellent candidate app to build with all three UI toolkits, as it:

  • Needs various UI elements, like menus, lists, dialogs, bottomSheets, etc.
  • Features a Canvas, where the map is displayed, so it involves custom drawing, event handling, gesture listeners, path operations, and all the good stuff.
  • Fetches data (today’s game) via the internet using Firebase services. Also reads various JSON files, so we can check how each framework handles I/O and async operations.
  • Incorporates in-app purchases and ads, so we can also take a look at integrating third-party packages.

The goal is to develop MapGame as a native mobile app with Jetpack Compose and SwiftUI, and launch it on the Play Store and App Store respectively.

As for the Flutter version, it is already available as a preview teaser in the MapChart mobile app, which is built with Flutter. It’s not the full-fledged game, but it still has most of the gameplay features of the game. Here it is in action:

Why go native for the MapGame app?

I indeed considered expanding the preview in the MapChart Flutter app into a full MapGame app.

I have developed various apps with Flutter, both for mobile and desktop, and I am experienced enough with it to quickly put together a new mobile app.

But I wanted to go native for this, for three reasons:

Performance

MapChart uses Flutter, and I can still see lag (jank) when zooming and moving around the map (relevant issue, now closed), especially on older Android devices. It’s one of the most frequent complaints and 1-star reviews I get for the app, and I haven’t been able to remedy this, even after implementing most optimizations I could find.

Impeller, Flutter’s new rendering engine, seems promising, but it’s not stable yet. It also looks like no more performance optimization work will be done by the Flutter team for Skia’s engine, since they are focusing now mostly on Impeller.

Playing a laggy time-based game is not optimal, of course. I want it to be as smooth as possible, to ensure a fun experience for users, and native seems the best choice.

Learning new things

I am not married to one technology. I want to keep my mind open and try new stuff when it makes sense.

As I said above, Jetpack Compose and SwiftUI are now the recommended solutions for building UI-focused apps on Android and iOS, so why not give it a go?

Also, I wanted to try out Kotlin and Swift. If I had to work with Java and Objective-C, as was the case before, I wouldn’t do it at all. But Kotlin/Swift are modern languages, full of features and I think they provide a developer experience on par with Dart.

Similarity with Flutter

All three toolkits implement declarative UI, each in its own way. There are even tools comparing how each one implements the various concepts and techniques.

Creating a new component in SwiftUI, Jetpack Compose, and Flutter. Source.


Since I am already used to reasoning about things like state management, composition, dependency injection, side effects, etc., it’s now easier to pick up and learn Compose and SwiftUI.

The Android app is out now

At this point, after almost two months of development, the MapGame Android app, built with Jetpack Compose, is now live on the Play Store:

Here is the announcement post on MapChart’s blog.

The app’s been live for about a week now, and you know how it is – I’m still playing whack-a-mole with some crashes and bugs. They’re the fun kind that only show up when a bunch of people get their hands on the app!

After that, I will sit down and write the next part of this series, detailing my experience with using Jetpack Compose to develop the app.

I’ll be sharing the good, the bad, and the downright odd about Kotlin and Compose, so stay tuned!