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.

Related Products
PSPDFKit for Flutter

Product Page
Guides
Example Projects

Share Post
Free 60-Day Trial Try PSPDFKit in your app today.
Free Trial

Related Articles

Explore more
PRODUCTS  |  Android • Releases

Android 2024.1 Update: Advanced Content Editing and Digital Signatures, Plus Expanded Jetpack Compose Support

TUTORIALS  |  Android • How To

How to Persist Zoom While Scrolling through a Document Using the PSPDFKit Android Library

CUSTOMER STORIES  |  Case Study • React Native • iOS • Android

Case Study: How Trinoor Uses PSPDFKit to Drive Operational Excellence with Flexible, Mobile Applications for the Energy and Utilities Market