How to capture screenshots for a Flutter app?

Me, trying to figure out, how to capture screenshots…

TL;DR: This is a story about how I made my own tool to capture screenshots on multiple devices. It’s not some kind of magic tool that can make screenshots fully automatically, it only starts the simulator/emulator and runs the UI tests on the booted device. Where exactly the screenshot capturing happens? It’s totally up to you. It depends on where you put a screenshot method call in your tests.
You can find more details under Usage and you can check the link of the project’s GitHub repository at the end of the story.

The problem

When you’re developing a mobile app, at a certain point, you may want to check your product’s appearance looks properly on multiple devices. Just to be sure, your creature looks good on every type and size of devices (e.x.: you want to support all series of iPhones).

I faced with this too, maybe same as you. So I started to search on the Net and found a few tools, but I wasn’t able to make them work.

The solution

After a few hours of trying and failing I felt like I stucked in an infinite loop, so I started wonder what I would expect from a screenshot tool? I made a few bullet points about what I need to do:

  1. If it is necessary create a schema about the device
  2. Boot more devices after each other
  3. Switch the theme of the os between light and dark
  4. Run the UI tests on the booted device and extend the test with screenshot taking
  5. Able to configure test runs for readable test results — pass the current device’s name and theme setup, so it puts the images to individual directories
  6. Stop the device after test done

It didn’t look like rocket science, so I started to implement it. I wanted to create a simple, straight forward tool so it was evident to create it in Go.

I started to work on the iOS support, fortunately Apple provides a pretty good CLI tool to manage simulators, it’sxcrun simctl. It gives you a lot of commands to control your virtual device.

On MacOS this command is available if you install Command Line Tools for XCode.

To run Android emulator, I found avdmanager to create and list existing AVD(Android Virtual Device), emulator for boot the device and adb for shutdown it. If you want to test on custom device setups, you should create the device setup and the avd manually.

If you want to run Android emulators, there are two possible options:

  1. Install Android Studio and set up the necessary environment variables
  2. Install only the command line tools for Android development and also set up the necessary environment variables, link here

It’s totally up to you, I’ll attach the mentioned variables with an example:

export ANDROID_HOME="$HOME/android"
export ANDROID_SDK_ROOT="$ANDROID_HOME/sdk"
# you can use specific version, instead of latest
PATH="$PATH:$ANDROID_SDK_ROOT/cmdline-tools/latest/bin"
PATH="$PATH:$ANDROID_SDK_ROOT/platform-tools"
PATH="$PATH:$ANDROID_SDK_ROOT/emulator"

Usage

  • (Optional) Go 1.16 (if you’re building it from source)
  • Installed Xcode with Simulator
  • Installed Android development environment (it can be Android Studio or only command line tools)

GO111MODULE=on go get -u -t github.com/borosr/flutter-screenshot

All releases are available here.

Linux/Mac

wget https://github.com/borosr/flutter-screenshot/releases/download/{RELEASE}/flutter-screenshot_{RELEASE}_{OS_KIND}_{ARCH}.tar.gz -O ~/Downloads/flutter-screenshot.tar.gz
tar -xzvf ~/Downloads/flutter-screenshot.tar.gz flutter-screenshot
mv ~/Downloads/flutter-screenshot /usr/local/bin/flutter-screenshot

Windows
Download and extract the release.

You can use flutter-screenshot init for the configuration file creation. This will generate a screenshots.yaml file in your current position.

Or do it manually:

Name it screenshots.yaml

The value of the command field will be executed after the virtual device started

command: flutter drive --target=test_driver/app.dart
devices:
ios:
- name: iPhone X
mode: both
- name: iPad Pro (12.9-inch) (4th generation)
mode: dark
android:
- name: Pixel

You can use flutter doctor to make sure every environment variables and commands are properly set. This command will check them and display the result on the console. You should see something like this:

INFO[0000] Checking iOS commands are on path...
INFO[0000] xcrun: ✅
INFO[0000] Checking Android environment variables...
INFO[0000] JAVA_HOME: ✅
INFO[0000] ANDROID_HOME: ✅
INFO[0000] ANDROID_SDK_ROOT: ✅
INFO[0000] Checking Android commands are on path...
INFO[0000] emulator: ✅
INFO[0000] adb: ✅

For example:

Note: You can use EMU_DEVICE environment variable to group the captured images, it contains the running device’s name and the theme setup in snake_case format. e.x.: iPhone_X_dark

final now = new DateTime.now();
Future<void> makeScreenshot(FlutterDriver driver, String filename) async {
final imageInPixels = await driver.screenshot();
new File('screenshots/${Platform.environment['EMU_DEVICE']}_${now.toString()}/$filename.png')
.writeAsBytes(imageInPixels);
}

You can use --verbose flag to get more log messages

The --config flag is optional and it waits your configuration file’s path, so you can put anywhere and/or rename your configuration file.

flutter-screenshot [--verbose] [--config/-c]

Plans for future

I have a few more ideas that can make this tool even better. Such as parallel device running or changing the device’s orientation.

I’m also open for opinions and proposals, so don’t be shy and share your experiences with me! If you want to contribute to project, check the GitHub link down.

Gopher, software engineer, remote worker. Likes science and technology.