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:

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.

iOS

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.

Android

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:

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

Pre-requirements

  • (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)

Install the tool from source

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

Install the prebuilt release from GitHub

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.

Add configuration to your flutter project

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

Test your setup before continue

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: ✅

Implement a custom helper method in your UI tests

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);
}

As last step, execute the following command

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.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store