Blog Post

Run a Flutter App on an Emulator inside Docker

Illustration: Run a Flutter App on an Emulator inside Docker

When building Continuous Integration (CI), you might find yourself needing to run your application on an emulator in use cases such as automated UI testing or generating screenshots. In this blog post, I’ll walk you through how to easily dockerize your Flutter application and run it on a dockerized Android emulator.

We’ll start by creating a new Flutter project, so make sure you have the Flutter environment set up with the latest version of Flutter. You can check your setup by running flutter doctor, which gives you information about which version of Flutter is installed and how to update it if it isn’t the latest.

Go to your terminal at any desired location and run flutter create mydockerisedapp to create a new Flutter application. You can also use File > New > New Flutter Project… in Android Studio, or use Visual Studio Code to create a new Flutter project.

This setup will require two Docker containers: one to run the application, and another for the Android emulator.

Flutter Docker Image

First, set up the Flutter application Dockerfile, which contains the setup instructions for our Flutter Docker image:

FROM ubuntu:20.04

ENV DEBIAN_FRONTEND="noninteractive"
ENV JAVA_VERSION="11"
ENV ANDROID_TOOLS_URL="https://dl.google.com/android/repository/commandlinetools-linux-7583922_latest.zip"
ENV ANDROID_VERSION="29"
ENV ANDROID_BUILD_TOOLS_VERSION="29.0.3"
ENV ANDROID_ARCHITECTURE="x86_64"
ENV ANDROID_SDK_ROOT="/usr/local/android-sdk"
ENV FLUTTER_CHANNEL="stable"
ENV FLUTTER_VERSION="3.0.2"
ENV GRADLE_VERSION="7.2"
ENV GRADLE_USER_HOME="/opt/gradle"
ENV GRADLE_URL="https://services.gradle.org/distributions/gradle-${GRADLE_VERSION}-bin.zip"
ENV FLUTTER_URL="https://storage.googleapis.com/flutter_infra_release/releases/$FLUTTER_CHANNEL/linux/flutter_linux_$FLUTTER_VERSION-$FLUTTER_CHANNEL.tar.xz"
ENV FLUTTER_ROOT="/opt/flutter"
ENV PATH="$ANDROID_SDK_ROOT/cmdline-tools/latest/bin:$ANDROID_SDK_ROOT/emulator:$ANDROID_SDK_ROOT/platform-tools:$ANDROID_SDK_ROOT/platforms:$FLUTTER_ROOT/bin:$GRADLE_USER_HOME/bin:$PATH"

# Install the necessary dependencies.
RUN apt-get update \
  && apt-get install --yes --no-install-recommends \
    openjdk-$JAVA_VERSION-jdk \
    curl \
    unzip \
    sed \
    git \
    bash \
    xz-utils \
    libglvnd0 \
    ssh \
    xauth \
    x11-xserver-utils \
    libpulse0 \
    libxcomposite1 \
    libgl1-mesa-glx \
  && rm -rf /var/lib/{apt,dpkg,cache,log}

# Install Gradle.
RUN curl -L $GRADLE_URL -o gradle-$GRADLE_VERSION-bin.zip \
  && apt-get install -y unzip \
  && unzip gradle-$GRADLE_VERSION-bin.zip \
  && mv gradle-$GRADLE_VERSION $GRADLE_USER_HOME \
  && rm gradle-$GRADLE_VERSION-bin.zip

# Install the Android SDK.
RUN mkdir /root/.android \
  && touch /root/.android/repositories.cfg \
  && mkdir -p $ANDROID_SDK_ROOT \
  && curl -o android_tools.zip $ANDROID_TOOLS_URL \
  && unzip -qq -d "$ANDROID_SDK_ROOT" android_tools.zip \
  && rm android_tools.zip \
  && mv $ANDROID_SDK_ROOT/cmdline-tools $ANDROID_SDK_ROOT/latest \
  && mkdir -p $ANDROID_SDK_ROOT/cmdline-tools \
  && mv $ANDROID_SDK_ROOT/latest $ANDROID_SDK_ROOT/cmdline-tools/latest \
  && yes "y" | sdkmanager "build-tools;$ANDROID_BUILD_TOOLS_VERSION" \
  && yes "y" | sdkmanager "platforms;android-$ANDROID_VERSION" \
  && yes "y" | sdkmanager "platform-tools"

# Install Flutter.
RUN curl -o flutter.tar.xz $FLUTTER_URL \
  && mkdir -p $FLUTTER_ROOT \
  && tar xf flutter.tar.xz -C /opt/ \
  && rm flutter.tar.xz \
  && git config --global --add safe.directory /opt/flutter \
  && flutter config --no-analytics \
  && flutter precache \
  && yes "y" | flutter doctor --android-licenses \
  && flutter doctor \
  && flutter update-packages

Now, your Dockerfile is set up.

Emulator

For the emulator, we’ll use an open source emulator image provided by Google. This will run as a separate Docker container, and we’ll connect to it from our Flutter application over a Docker network using adb.

ℹ️ Note: This setup requires KVM, which is only available on Linux (Ubuntu and Debian), and therefore won’t work on Mac and Windows machines.

Docker Compose

Next, we’ll set up a docker-compose.yml file to run the containers together:

version: '3.6'

services:
   app:
      build:
         context: '.'
         dockerfile: Dockerfile
      image: 'flutter'
      working_dir: 'app'
      depends_on:
         - emulator
      volumes:
         - './:./app'

   emulator:
      image: us-docker.pkg.dev/android-emulator-268719/images/30-google-x64:30.1.2
      expose:
         - 8554/tcp
         - 5555/tcp
      devices:
         - '/dev/kvm:/dev/kvm'
      env_files:
         - .env

As you might notice, the Flutter application app depends on the emulator service, and they’re linked by a Docker network. There’s no need to define any networks, because Docker Compose will automatically create a default network.

Bash Script

Lastly, we’ll set up the run.sh script with the commands needed to run the application:

#!/bin/bash

# Connect to the Android emulator container.
adb connect emulator:5555

#List the available Flutter devices. You should see the connected dockerized emulator.
flutter devices

# Install the Flutter packages.
flutter pub get

# Run the Flutter app on the connected emulator.
# Add `--trace-startup` to stop the Flutter process from blocking the terminal.
flutter run --trace-startup

mkdir -p 'screenshots' || exit 1

# Take a screenshot of the Flutter app.
adb shell screencap /sdcard/screenshot.png

adb pull /sdcard/screenshot.png screenshots/flutter-screen.png

Now, add execute permissions to run.sh by running chmod +x run.sh

Running the Application

Finally, run the application as shown in the script below:

$ docker compose run app run.sh

This will set up the Docker containers and execute run.sh inside the app container. Wait for the execution to complete, and you’ll see the flutter-screen.png image file in the screenshots folder.

Conclusion

In this blog post, we looked at how to run a dockerized Flutter application on a dockerized Android emulator. The setup can be used for purposes such as automated UI testing and automatically generating screenshots.

FAQ

How do you set up the Docker environment for a Flutter app?

You set up the Docker environment by creating a Dockerfile for the Flutter app, an emulator image, and a docker-compose.yml file to manage the services. The Dockerfile sets up the necessary dependencies and configurations, while the docker-compose.yml file defines the services and their relationships.

What is the role of the run.sh script in this setup?

The run.sh script contains the commands to connect to the Android emulator, list available Flutter devices, install Flutter packages, run the Flutter app, and take screenshots. It is executed inside the Docker container to automate these tasks.

Can this setup be used on Windows or Mac machines?

No, this setup requires KVM, which is only available on Linux (Ubuntu and Debian). It will not work on Mac or Windows machines.

How do you run the Flutter app on the dockerized emulator?

After setting up the Docker containers, you can run the Flutter app by executing the run.sh script inside the app container using the command docker compose run app run.sh. This will build and run the app on the connected Android emulator.

How do you generate a screenshot of the Flutter app in this setup?

The run.sh script includes commands to take a screenshot of the Flutter app running on the emulator. It uses adb shell screencap to capture the screen and adb pull to retrieve the screenshot from the emulator to the local system.

Author
Julius Kato Mutumba Native Engineer

Julius joined Nutrient in 2021 as an Android engineer and is now the Cross-Platform Team Lead. He has a passion for exploring new technologies and solving everyday problems. His daily tools are Dart and Flutter, which he finds fascinating. Outside of work, he enjoys movies, running, and weightlifting.

Related products

PSPDFKit for Flutter

Product page Guides Example Projects

Share post
Free trial Ready to get started?
Free trial