As we saw in the last chapter, Flutter enables us to create apps that run on the Web, on desktop computers, and on mobile devices (which seems to be the main draw). But wait a second, how exactly do we create these apps? What editor should we use? What is needed in the Flutter project? How do you compile the Dart source code? Do we need any other tools to support the project? How do you get it into a browser or on a device in order to test it out? Good questions, right?
- 1.
Tools needed – How to install and maintain them
- 2.
The development process – How to create the app, run it, and debug it
Caution
By its nature, cross-platform app development tooling involves an awful lot of moving parts from various organizations, few of whom consult with the others before making changes. And since we’re dealing with boundary-pushing and young technology, changes happen frequently. We’ve tried in this chapter to stick with timeless information but even it is likely to become stale eventually. Please check with the authors of these tools for the latest and greatest information.
The Flutter toolchain
There is no end to the list of helpful tools that the development community has produced. It is truly overwhelming. We’re making no attempt at covering them all. We want to give you just enough for you to be proficient but not so many that you’re overburdened. Forgive me if I’ve skipped your favorite.
The Flutter SDK
The Flutter SDK is the only indispensable tool. It includes the Flutter compiler, project creator, device manager, test runner, and tools that diagnose – and even correct – problems with the Flutter configuration.
Installing the flutter SDK
The installation instructions are found here: https://flutter.dev/docs/get-started/install. Long story short – it will involve downloading the latest zip file of tools and setting your PATH to point to the folder where you unzipped them. The steps vary per operating system, but they’re very plain on that web site.
Tip
This step seems very low level and sounds intimidating, but after this step, things get easier and less error-prone. Don’t let it discourage you.
IDEs
In theory an IDE isn’t really needed. Flutter can be written using any editor and then compiled and run using the flutter SDK that you installed earlier. But in reality almost nobody ever does that. Why would they? The following IDEs have Flutter support built right in!
VS Code from Microsoft
VS Code is from Microsoft. Its official name is “Microsoft Visual Studio Code,” but most of us just call it VS Code. Whatever you call it, please do not confuse it with Microsoft’s other product called “Microsoft Visual Studio.” They are not the same thing regardless of the similar names.
You can get VS Code here: https://code.visualstudio.com.
Android Studio/IntelliJ from JetBrains
Android Studio and IntelliJ are essentially the same thing. They are built from the same codebase and have the same features.
You can get Android Studio at https://developer.android.com/studio and IntelliJ IDEA here: www.jetbrains.com/idea/download.
Which IDE should I use?
Both VS Code and Android Studio/IntelliJ are free and open source. Both run cross-platform on Windows, Mac, and Linux. Both are roughly equally popular with Flutter developers,1 neither having a clear market advantage over the other. You can’t go wrong with either one.
But if you must choose one, what we’ve found is that your background may affect how you like the tools. Developers from the web development world, those who use tech like HTML, CSS, JavaScript, NodeJS, React, Angular, or Vue, strongly prefer VS Code. On the other hand, those developers who came from a Java world, especially Android developers, seem to lean toward Android Studio/IntelliJ.
The good news is that this is a very low-pressure choice. It is trivial to switch editors – even while working on a given project. Start in one and see how you like it. If you don’t, you can give the other a test drive for awhile. Go back and forth a couple of times until you have a strong preference. It’s really no big deal to switch.
IDE DevTools
While those IDEs are great, they’re not built for Flutter exclusively; they’re used for developing in other languages and frameworks as well. So to improve the Flutter development flow, we should install the Flutter DevTools. It adds in debugger support, lets you look at logs, connects seamlessly with emulators, and a few more things.
You may need to restart the IDE after you install .
Emulators
Once you’ve got the IDE and DevTools installed, you’re ready to compile your app. But to run it, you need to get it on a device. An emulator – a virtual device that runs on your laptop/desktop – makes it really easy to run, test, debug, and show your app. You’ll probably want to test on both iOS and Android, so you’ll need emulators for each. There are several emulators available, but I’ll mention just a couple, Xcode’s iOS simulator and AVD’s Android emulator.
iOS simulator
Android emulator
Just like there are tons of Android models, so are there tons of Android emulators, but there are only two popular ways to interact with them: Genymotion and AVD Manager. Genymotion is a for-profit company, so when you visit their web site, they’ll do their level best to steer you toward their paid version. That’s understandable. We’ll focus on AVD Manager because it is totally free and more popular with Flutter devs.
Hit it and you can choose from all kinds of devices or create one of your own. You’ll only need to install a device once. After it’s installed, that emulated device is usable from any IDE, whether IntelliJ/Android Studio or VS Code. No need for a separate setup on VS Code.
Keeping the tools up to date
Early on, cross-platform development with tools like Xamarin and React Native was terribly difficult because of the sheer number of the tools involved and the interdependencies between them. I’m still in therapy from the pain.
But because Flutter arrived on the scene later it can learn from others’ mistakes. The Flutter team, recognizing these pain points, gave us an innovative tool to manage the rest of the toolchain. It will examine your development machine, looking for all the tools you’ll need to develop Flutter apps, the versions you have, the versions that are available, the interdependencies between them, and then make a diagnosis of problems. It will even prescribe a solution to those problems. Kind of sounds like a doctor, right? Well, let me introduce you to flutter doctor!
flutter doctor
The “No devices available” error is common, and you can usually ignore that one. It just means that at that moment no emulators were running.
flutter doctor not only detects and reports problems but it usually prescribes the fix for each. It will even tell you when it is time to upgrade itself via “flutter upgrade.”
flutter upgrade
Note that flutter doctor is automatically run as the last step, confirming that all is well. Upgrading is a piece of cake.
The Flutter development process
Now that we have all the tools installed and up to date, let’s create an app and run it through the debugger.
Scaffolding the app and files
This will create a subfolder under the current folder called my_app. It will be full of ready-to-run Dart code.
Tip
The app name is case insensitive, so you should make it all lowercase. Dashes are illegal characters, so you can’t use kebab-casing. The recommended casing is lowercase_with_underscores.
Anatomy of a Flutter project
android and ios – These are the platform-specific parts of the project. For the most part, you won’t need to touch these.
lib – This is the home of all of your Dart source code. You will build your app’s hierarchy here. This is where you’ll spend nearly all of your time and attention.
test – If you have unit tests (and you probably should eventually), put them here.
pubspec.yaml – This is essentially the project file for Dart projects. This is where we set our project name, description, dependencies and more. Be sure to read the comments in here to get a better picture of what is suggested and possible.
.gitignore and README.md – These will be very familiar to devs who use git and github for their source code repository. Others won’t care.
.metadata and .packages – These are important config files which you’ll never open. But Flutter needs them.
Tip
There’s one more file you should be aware of: analysis-options.yaml. Having this file is not required, but if you do, you’ll write better code. This file signals the IDE to perform linting (aka static analysis) on the code as you write it. With analysis-options.yaml, the IDE will warn you when you don’t use best practices.
Rather than writing one from scratch, let me suggest that you start with someone else’s. Here’s one that is very popular with the Flutter community: https://github.com/flutter/plugins/blob/master/analysis_options.yaml.
It is aggressive. If you want to turn off some of the rules, just delete the lines or comment them out. An explanation of all of the linting rules can be found here: http://dart-lang.github.io/linter/lints/.
Running your app
Obviously you’ll need to run your app in a device of some kind. There are several: the Chrome browser for a web app, emulators, or a physical device that is tethered to your development machine via a cable. When you click the Play/Debug button, you get to choose which device you want to run at that moment. Notice that in the preceding screenshot of Android Studio, there’s a dropdown menu with a list of available devices. In VS Code, hit the Play button, and a menu immediately pops up with your choices. With either IDE, you are in control.
Tip
You can check what devices are currently available to you by running “flutter devices” from the command line.
$ flutter devices
3 connected devices:
Vivo XL3 • 55S...KF • android-arm64 • Android 8.0.0 (API 26)
Android SDK • emul...4 • android-x86 • Android 9 (API 28) (emulator)
iPhone X • E6...39A • ios • com.apple...OS-12-1 (simulator)
The preceding sample output tells us that we have three devices. The first and second are Android devices and the third runs iOS. The first device is a tethered physical device. The second and third are emulators.
No te that this command is different from the “flutter emulators” command which tells you all possible emulators you could potentially choose from. The flutter devices command tells you which devices are currently available to run your app.
Running it as a web app
From then on, when you get a list of devices on which to run your app, “Chrome” will appear as one of them. Simply choose to run your app in Chrome and the IDE will load your web app in it.
Running it on a tethered device
There are times when you need to run your app on a physical device. For example, I was developing a project that involved printing labels to a physical printer connected by Bluetooth. Emulators don’t pair via Bluetooth. To test the printing, I needed an actual physical device that was already paired to my Bluetooth printer.
To tether a physical device to your development machine, you’ll use a USB cable for most Android devices and a Lightning cable for most iPhones.
Tips
#1 When connecting an Android device, it will initially think you’re trying to charge it or transfer photos. To let it know you’re trying to debug, open the Developer Options screen on the device and select “Enable USB debugging”.
#2 Many connection issues can be caused by an inferior USB cable. Counterintuitively, not all USB cables are created equal. Switch to a higher-quality cable if you still can’t connect after changing settings.
Hot reloading
Once the app is running in your emulator/browser/physical device/whatever, you’ll want to make changes to the source code and rerun. Here’s the really cool thing: any time you save a change to the source code, it is recompiled and the new version is loaded instantly. Your app picks up where you left off – in the same spot, with the same state, and same data. We call it “hot reloading,” and it makes the development cycle ridiculously fast and frictionless.
Debugging
Both IDEs have essentially the same debugging tools you’ve become accustomed to in all IDEs. When you start your project running, the debugging tools will appear.
The options are “step over,” “step into,” “force step into,” and “step out” from left to right.
Its options are “play/pause,” “step over,” “step into,” “step out,” “hot reload,” “restart,” and “stop debugging.”
Note
Flutter is pickier when you’re debugging than when running for real in a device. This is a good thing because during debugging it makes obvious certain errors that you should probably fix but aren’t necessarily fatal. In the release version, it swallows those same errors and (hopefully) allows our users to continue running our app.
One family of those errors is “runtime assertions.” You’ll know you’re dealing with one of these when the debugger gives you an error like this:
════════ Exception caught by gesture ════════
The following assertion was thrown while handling a gesture:
setState() callback argument returned a Future.
The setState() method on _FooState#236 was called with a closure or method that returned a Future. Maybe it is marked as "async".
etc. etc. etc.
Your takeaway is this: when you see one of these, fix the problem. It’s the right thing to do. But don’t be confused if you don’t see that same problem after you’ve deployed it.
Conclusion
Look, I know that this is a lot of stuff to absorb. The nature of cross-platform development makes the tooling hairy. But the worst is behind us. Once you’ve got the Flutter SDK and an IDE (VS Code/Android Studio/IntelliJ IDEA) installed, that’s all you really need. And granted, the DevTools and an emulator or two can really help. All that’s left is getting some repetitions in for practice. You’re going to be great!
So now that we’ve seen the Flutter toolchain, let’s start creating widgets!