When launching a product, you have a huge number of engineering choices to make. For some of these, you just have to make a bet and hope it works out.
One bet we made early on was to use Flutter to build the companion app for Tidbyt. I'm happy to say that it's really worked out. In fact, at this point I would say that Flutter is the perfect tool to build companion apps for Internet-of-Things (IoT) devices.
It's not all sunshine and rainbows. There are a lot of potential traps. But overall, we've found that Flutter fits really well for IoT in particular. Especially if you're self-funded or working on a bootstrap budget.
This is a bit beyond the scope of this post, but if you haven't heard of it, Flutter is a framework for building cross-platform apps. It primarily targets Android and iOS, though it also has some support for web and desktop apps.
It's often compared to React Native, but there are a couple of key differences. Flutter apps are written in Dart, which is compiled to native code. And all UI widgets are rendered by Flutter, as opposed to using native widgets.
The uncompromising demands of hardware
The phrase "hardware is hard" is cliché at this point, but there is truth to it. Something I often hear is that when you're building a hardware company, you're taking on the difficulty of building both a physical product and a software product, combined. But in fact, building hardware is actually even more effort than that — at least if you don't want to do a crap job.
To see why, imagine a typical software startup that has a mobile app. This startup's engineering department will need to build:
- Backend services. Almost every software startup has some sort of cloud backend that does the heavy-lifting and powers its frontend.
- An iOS app. Many projects still launch for iOS first, and then build an Android app if and when the product gets some traction. This is a fairly reasonable way to save money and launch quickly.
But for a hardware startup like ours, you also need an Android app from the get-go. Sure, you could try to sell your hardware to only iPhone owners, but that's pretty impractical.
Your hardware is probably sold on your website, or on Amazon or Kickstarter or another retail location. Unlike the App Store, those venues aren't already gated to just iOS users. Think about how silly it would be for an Android user to purchase your hardware and discover that they could only get full functionality if they also bought an iPhone. Even AirPods work with Android (given, the Apple Watch is a notable exception).
You can tackle this by having two independent, fully-native apps for iOS and Android, but those are two additional skillsets you're going to have to add to your team. And that's on top of the other additional deliverables that you need as a hardware company:
- Physical product. This is pretty obvious, but a hardware company needs to build a physical product. This is going to involve some combination of electronics design for the guts of your device, and industrial design for the enclosure and any special features.
- Firmware. Your pretty hardware isn't going to do anything without some firmware to run on it. This is a whole software project in itself.
Each of these deliverables requires a completely different set of skills. So if you want any chance of getting your IoT product off the ground, you're going to need either a ton of funding to hire several engineers, or you'll need to have some people wearing multiple hats. This is where Flutter comes in and makes things easier in two big ways.
First and most obviously, Flutter reduces the effort of releasing both an Android and iOS app. Having a single codebase for both platforms gives you a productivity boost in implementing the UI.
The other benefit of Flutter is a bit more subtle. Because of the way it works, Flutter is relatively straightforward for engineers of many backgrounds to pick up. Because of this, potentially anyone on a small team can pitch in and contribute to a Flutter app.
While we checked out React Native — the other big player in the cross-platform space — the learning curve was much steeper given that nobody on our team has a deep frontend engineering background. Using React Native really requires you to delve deep into the JS ecosystem and learn multiple tools, and that is an entire universe unto itself.
Building IoT apps with Flutter
If you'e ever setup a smart device like a Google Home, Amazon Alexa, Philips Hue lightbulbs, or a smart switch, you know the general requirements for an IoT companion app. The app needs to connect to a nearby device, pair with it and configure it. Sometimes this happens over a Wi-Fi, sometimes over Bluetooth, and sometimes via a wacky sequence of strobing lights.
Our app isn't much different in this regard. Users need to connect to Tidbyt and configure it with their Wi-Fi SSID and password. But there's two things we discovered while building the app:
- Pairing and setup over Bluetooth LE is much smoother than over a Wi-Fi virtual AP. Switching back and forth between Wi-Fi networks can be jarring and often requires user intervention. Bluetooth LE has a much smoother "just works" experience.
- Flutter doesn't have Bluetooth support built-in, so picking the correct third-party Bluetooth plugin is very important. There are a number of corner cases when interacting with native Bluetooth API's, and the plugin needs to handle these correctly.
We initially chose flutter_blue, but ran into a number of difficult-to-reproduce issues. We ended up switching to flutter_ble_lib. The latter is built on top of RxAndroidBle and RxBluetoothKit, which are solid and widely-deployed native libraries.
No silver bullet
While Flutter definitely was a huge productivity boost, it's not perfect. It's just as possible to make ugly, broken apps with Flutter as it is with any other toolkit. Our app improved by leaps and bounds once we brought on creative and UX consultants.
That said, one thing that has never been an issue is that our app is "not native". This is a frequent criticism of Flutter that floats around Hacker News and other engineering hangouts. The theory is that, since Flutter's UI doesn't use native widgets, it will "feel wrong" and users will be turned off.
This worry doesn't seem to be borne out in reality. In the many interviews we've had with our users, this hasn't come up once. All we've heard is that the pairing process for setting up a new device is quick and easy. No customers seem to think twice about the app being "native" or not.
The biggest actual Flutter issue we've run into is dealing with breakages in plugins. As I mentioned above, we use a third-party plugin for Bluetooth support. We use a handful of other plugins for services like Google Maps, Apple and Google sign-in, and Firebase.
Occasionally a new version of plugin — or a new version of Flutter or Xcode — will break some native plugin code. At that point we have to drop down into native-land and go figure it out. We've mitigated this by being more selective and only using high-quality, well-maintained plugins.
So while Flutter is no silver bullet, it's a bet that's definitely paid off for us. With a small team that needs to do hardware, firmware, and software, we would have been hard-pressed to build two separate mobile apps. Instead we've been able to focus our efforts on building one great mobile experience.