Over the three months or so since I joined the Flutter team, I’ve been trying to find as much hands-on time as possible to get familiar with the framework. Inevitably that leads to a GitHub account full of half-baked experiments that have helped me play around with various concepts but aren’t of much use to anyone.

About a month ago, Matan Luray, one of the amazing software engineers on the Dart team, publicly challenged me on Twitter to actually show up and ship something :)

I like a challenge, and the comment was a fair one! So that weekend I took a few hours to try and complete a real app from start to finish.

An unnecessary addition to the app store

I wanted to build something small enough that it wouldn’t be consigned to the pile of half-finished projects, but useful enough to be worthy of uploading. Casting around on GitHub, I came across this amazing list of free JSON APIs, which in turn led me to icanhazdadjoke, a web service that returns some of the most groan-worthy jokes on the internet. This seemed like a promising start for a Flutter app.

So I created Dad Jokes: for those occasions when you need a bad joke at your fingertips.

There are endless great tutorials and labs already out there that explain the fundamentals of Flutter building a Flutter app. So I’m going to assume you’ve followed one of those already and instead call out interesting elements of the app that highlight strengths of Dart and Flutter as a mobile toolkit.

Step 1: JSON call with decode

If you don’t have any jokes, then you don’t have a dad joke app :)

The icanhazdadjoke API is really simple, which makes it great for a tutorial app. It doesn’t require authentication, and just accepts a simple HTTP GET request to retrieve a joke embedded in a simple JSON payload.

Dart makes it really easy to use an API like this, using its support for asynchronous HTTP requests and parsing JSON. Here’s the concise version of the code:

If you run this from an internet-connected machine, you should see something like the following:

Step 2: asynchronous UI with FutureBuilder

The above code works great for a console application. But it’s not sufficient for a mobile app, because your app can’t simply freeze with no visual progress while it waits on the web request to return a result.

That’s where Flutter’s FutureBuilder class comes in. FutureBuilder provides a widget that does all the heavy lifting to support asynchronous Future objects. The nice thing about FutureBuilder is that is can be added directly to the widget tree, and based off the current status of the connection, the relevant UI can be displayed to indicate progress, a result or an error. See the code below for a simple example:

This demonstrates the essentials, although the actual app has more visual styling applied and handles error conditions more gracefully.

Step 3: sharing a bad joke with others

It’s taken an amazingly small amount of code to get to this point: a mobile app that works on both iOS and Android, that makes an asynchronous call to a web service, interprets its response and updates the display intelligently based on the results.

Since we’ve got so much done with so little code, let’s go a step further. Flutter already has a strong ecosystem of packages that let you take advantage of someone else’s hard work for common tasks. A bad dad joke deserves to be shared widely, and so I grabbed the share package and declared a dependency on it in my application.

Astonishingly, it’s just three lines of code to add iOS and Android sharing support in your application. Firstly, you add a dependency to the package manifest:

Then within the app itself, you declare a reference to the package, add a button to call the share action, and then use the button event handler to call the share() method.

That’s all there is to it! The package takes care of all the work of popping up the appropriate overlays on iOS and Android to select an app to share with and passing the relevant content across.

Step 4: embedded fonts

A cheesy joke deserves a cheesy font. It’s arguable that Comic Sans is the only font fitting for an app like this, but it isn’t freely available for distribution.

The good news is that Google Fonts has hundreds of open source designer fonts available for usage in this kind of context, from the playful to the corporate. I rather enjoyed Patrick Wagesreiter’s handwriting-inspired font, Patrick Hand, so I thought I’d incorporate it in the app.

This also proves to be rather trivial — after downloading the font and dropping the TTF file in the assets/ folder, you declare it in the package manifest, like so:

For ease of reuse, I named the text style and then applied it to the Text widget that displayed the joke:

That pretty much wraps up the core logic of the app — with the exception of a refresh button that triggers a new joke:

And now we have a working app that looks something like this:

Step 5: Swipe left for another awful joke

When I showed my app off to some friends, I was surprised to observe them swiping at the screen. I hadn’t anticipated that my dad jokes were as good as a hot Tinder date, and that the refresh button wasn’t obvious to some people.

Fixing this seems like a fair amount of work — in addition to detecting and handling the swipe touch gesture itself, the app now needs to move the joke off the screen in the direction of the swipe; and there needs to be some kind of threshold for when a swipe is far enough to trigger a refresh and when it snaps back again. And all this needs to be done in an appropriate manner for the device platform and form factor.

But (and you’re probably sensing a theme here), Flutter takes care of all those low-level details that are needed to build a polished application. In particular, the Dismissible widget provides exactly what we need here. All we have to do is to wrap the Text widget in a Dismissible parent, and all those details are taken care of for us:

Step 6: Publishing the app

With a finished app in hand, the final step of publishing it proved surprisingly time-consuming. Don’t underestimate the work needed to navigate both app stores, sign and upload the finished application packages, create catalog entries and metadata and so on. And unfortunately, this is where you do have to do things twice, because Flutter builds a native bundle for each platform (both an APK and an IPA file).

A few tips from my own experiences with the app:

There are two very comprehensive articles on the Flutter website that go through the final steps of creating and packaging a release version of your app for submission to each store: one for iOS, and the other for Android.

Apple in particular require a ton of different icon assets for various device resolutions. I had great success with MakeAppIcon, which lets you upload a single high-resolution image and then sends you a ZIP file containing all the various scales required.

Similarly, well-polished app store entries have carefully selected images that showcase the app. While we could just take screenshots of the app itself, I found ShotBot, which does a nice job of creating a polished image that includes your screenshot and a bit of marketing blurb, like this one:

Live from an app store near you… it’s Dad Jokes!

As simple as this app is, it’s been good fun to build, and it’s always rewarding to see the download count creep up for something you’ve built for has been available on the store. The rock musician Sting once gave an interview where he described the thrill, as a fledgling artist, of hearing a hospital janitor whistling one of his songs as he mopped floors. As an app creator, there’s something of that same reward in releasing something to the world, no matter how small.

OK, so this app is not going to the “Roxanne” of the app store any time soon, but perhaps it’s a useful example of building something small in Flutter and taking it all the way to completion. If you’re interested in downloading the app or looking at its source code, I’ve provided the links below.

And lastly, when does a joke become a dad joke?

When it becomes apparent. 😝