Making a Spaceteam timer app with Flutter

By: on January 4, 2019

Some of you may have run into the excellent Spaceteam mobile game. It’s best described as ‘co-operatively shouting at each other to fix your broken ship’, and it’s a lot of fun. Some fun folks then went and made a card game variant of it, which is similar in many ways. Now, both games have a time limit involved to fix your ship, which in the card game variant is done by a sand timer. This a) only allows for the five minute ‘medium’ version of the game and b) doesn’t quite add the same interesting background noises that the mobile one did. To solve this, they provided a series of countdown timer sound files on their website, which both give you 3/5/7 minute variants, but also add bits of atmospheric noises and ‘one minute remaining’-type utilities, which enhances the experience somewhat. This works well on mobile phones, but less well in the basements of London pubs that aren’t built for mobile signal. Partially to solve this, and mostly to give me an excuse to learn Flutter, I’ve now built an app that does this for you offline.

Flutter is a cross-platform (iOS, Android, and eventually Fuchsia) mobile development system. It achieves this by acting more like a game engine than a mobile app, rendering all your widgets directly rather than using the operating system widgets. Despite sounding like a bad idea, it works rather well.

The first thing you run into when building your Flutter app is the use of Dart. For those of you who haven’t heard of it before, it used to be Google’s attempt to kill Javascript, but they’ve since mostly given up on that, and the major focus of all things Dart these days is Flutter (well, with some exceptions, but I’m yet to find one of those not run by Google devs). If you’ve written both Java and Typescript, it’ll feel mostly familiar, and I’ve been able to pick it up pretty quickly.

There’s a few good/bad bits:

  • Good hot reload support—I’d call it excellent, but I’ve used Clojurescript/Figwheel. It’s excellent in comparison to most Javascript equivalents.
  • Weird import paths—so, they either start ‘package:’ for external packages (or ‘package:flutter’ for framework ones), ‘dart:’ for language internal libraries, or a plain path for your own files. From this, you might expect the import for flutter_sound to be “package:flutter_sound”? Nope, it’s ‘package:flutter_sound/flutter_sound.dart’, for no good reason.
  • Occasional errors of the form ‘error: Unexpected tag 0 (Nothing) in ?, expected expression’ for reasons unknown. A quick ‘flutter clean’ fixes them, but it’s disconcerting.
  • Sometimes, the commands get stuck—so, the ‘flutter’ command magically does stuff for you. Which is great when it works, but when you’re on a poor network connection and it looks like it’s locked up, but actually it’s just gradle downloading half the internet, it’s really hard to tell. Adding ‘-v’ (e.g. ‘flutter run -v’) or just doing “flutter doctor -v’ to double-check you’ve got all the other tools it wants installing helps a lot.
  • The flutter API docs are a mix of builtin libraries and external ones. Pay a lot of attention to the documentation at the module level, not just the class level to find this out (e.g. DateFormat is in the external intl library)
  • If you install a new package, restart your build completely. If you don’t do this, and the package had anything platform-specific, you’ll get the fun MissingPluginException. The VSCode extension for Flutter, which is otherwise brilliant (hurrah for autoformat-on-save!) doesn’t spot this.

Overall experience has been good. A few rough edges, and I haven’t tried building my own platform-specific stuff, but I’m enjoying it so far, and the time from first code to “deployed to the app store” was about a week, which is rather good. Code for all of this is in the usual sort of place.


Leave a Reply

Your email address will not be published.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>