Flutter application in a docker container on an IMX8 on Torizon

Apalis iMX8
Ixora Carrier Board V1.2
TorizonCore with evaluation Containers

I am evaluating using Flutter on an i.MX 8QM embedded device. My development machine is a virtualbox ubuntu guest. The i.MX is running TorizonCore with evaluation containers and I am able to run docker containers both on my host/dev machine and target.

I tried following the instructions in blog post Flutter on Torizon - A PoC Setup for i.MX8M Plus, but am unable to, because I could not find the referenced code. Is there a git repo where I can find the following:
1. The flutter_build_env container: Is there a container on dockerhub, or a Dockerfile available where I can build my own container with everything needed to cross-compile a flutter application?
2. The source for the internet radio application so that I can build the bundle? This is less important, because I can just use any flutter example.
3. docker_compose_flutter.yaml (only a portion was revealed in the post)

Is there an example elsewhere that has instructions for running Flutter on an IMX.8 on Torizon?

Thanks in advance,
Dawn

Hi @dawnhowe_alten , that blog came from our partner Crossware.io. You may have to approach them for the resources. We have another blog about bringing up a flutter demo on Torizon and everything is open. Unfortunately, it is now only in Chinese. Google Translate or ChatGPT may help. Let me know if any help is needed.

As mentioned by Benjamin, the code source for that particular blog is closed-source by our partners at Crossware.io. You can contact them and see if they will supply the code. Otherwise there are alternate example codes that are open-sourced like this video player here: flutter-embedded-linux/examples/flutter-video-player-plugin at master · sony/flutter-embedded-linux · GitHub

Best Regards,
Jeremias

I am trying to replicate what this blog does as well since we cannot access the source (I tried the chinese blog but could not manage to make it work).

I am currently stuck on the docker compose file.

For the build environment container, I just made one and directly added a sample application to remove a step for this proof of concept. But you can just use it as a build environment anyway:
From an x86 host with docker engine

  1. Enable Arm emulation (docker run --rm -it --privileged torizon/binfmt)
  2. Build this dockerfile with docker buildx build --platform=linux/arm64 -t flutter-elinux:latest (or similar):
ARG BASE_NAME=ubuntu
ARG IMAGE_ARCH=linux/arm64/v8
ARG IMAGE_TAG=20.04
ARG DOCKER_REGISTRY=arm64v8

FROM --platform=$IMAGE_ARCH $DOCKER_REGISTRY/$BASE_NAME:$IMAGE_TAG
ARG IMAGE_ARCH

RUN apt-get -y update && apt-get install -y \
         build-essential \
         clang \
         cmake \
         curl \
         git \
         pkg-config \
         ninja-build \
         unzip \
         wget \
         libegl1-mesa-dev libxkbcommon-dev libgles2-mesa-dev \
         libwayland-dev wayland-protocols
         
RUN groupadd -r -g 1441 flutter && useradd --no-log-init -r -u 1441 -g flutter -m flutter
USER flutter:flutter
WORKDIR /home/flutter

# Flutter 3.3.10 needs to be used (at this sha in particular) because 3.7 has this open issue: 
# https://github.com/flutter/flutter/issues/116703 (as of 07.03.2023)
RUN git clone https://github.com/sony/flutter-elinux.git &&\
    cd flutter-elinux &&\
    git reset --hard 19a1b05ea20675c36c705955c4148ad40b205161 &&\
    cd ..
    
ENV PATH="${PATH}:/home/flutter/flutter-elinux/bin"
    
RUN flutter-elinux devices
RUN flutter-elinux doctor

RUN flutter-elinux create sample &&\
    cd sample &&\
    flutter-elinux build elinux
  1. From the x86 host: mkdir -p Flutter_torizon && cd Flutter_torizon and then, get the bundle that was built by the container with:
docker cp $(docker create --platform=linux/arm64 --name tc flutter-elinux:latest):/home/flutter/sample/build/elinux/arm64/release/bundle . && docker rm tc

The Dockerfile that’s inside the Flutter_torizon folder is the exact same (minus the naming) as in the blog post.

That’s the bundle folder and the Dockerfile done. But now I have no idea what to put in the Docker compose file. The blog says that the docker compose “command will run two images torizon/weston-vivante:2 and flutter_test:radio” (on target of course) but how exactly to reproduce this in the file?

In the Chinese blog, assuming Google translate worked correctly, there is a docker-compose.yml file shown at the end of the blog post.

docker-compose.yml
services:
flutter_demo_covid19:
  depends_on:
  - weston
  devices: []
  image: flutter_demo:1
  ports: []
  device_cgroup_rules:
  - c 199:* rmw
  - c 226:* rmw
  volumes:
  - /tmp:/tmp:rw
  - /dev/dri:/dev/dri:rw
  - /dev/galcore:/dev/galcore:rw
weston:
  cap_add:
  - CAP_SYS_TTY_CONFIG
  device_cgroup_rules:
  - c 4:0 rmw
  - c 4:7 rmw
  - c 13:* rmw
  - c 199:* rmw
  - c 226:* rmw
  environment:
  - ACCEPT_FSL_EULA=1
  image: torizon/weston-vivante:2
  network_mode: host
  volumes:
  - source: /tmp
    target: /tmp
    type: bind
  - source: /dev
    target: /dev
    type: bind
  - source: /run/udev
    target: /run/udev
    type: bind
version: '2.4'

This file appears to bring up 2 containers a weston container and then a second container running the flutter demo/application. So if you have a container built with the flutter demo inside then you can probably adapt this to your needs.

In your case however it looks like you have just the flutter application compiled output from your build environment container. In which case I see in the blog post there’s a set of docker run commands halfway through the blog. These commands take the flutter output/bundle and bind mount it into a weston container then run the application manually from inside this container.

Best Regards,
Jeremias

Thank you for your suggestion.

I did try with the docker-compose file you showed.

First, the dev environment container needed to use ARG IMAGE_TAG=20.04 instead of 22.04, to match libc6 and libstdc++6 versions with the runtime container.

However, running the docker-compose file on target (after loading the runtime container/image), I get this error:

torizon-flutter_demo-1  | embedder.cc (960): 'FlutterEngineCreateAOTData' returned 'kInvalidArguments'. Invalid ELF path specified.
torizon-flutter_demo-1  | Failed to create view controller.
torizon-flutter_demo-1 exited with code 0

Now, I am not sure what to do to continue.

I have no idea if this is the correct docker-compose file, but the line numbers line up with the post (put your image at line 47). Although this file ends at line 52, and the image in the blog has a couple more lines starting with “device_cgroup_rules:”

Hopefully this helps!

This sounds like an issue with how the Flutter application is executed or something similar as seen here: My Flutter Linux app works when running it using the flutter command but does not run when running by double clicking · Issue #62121 · flutter/flutter · GitHub

Looking again at the Chinese blog there’s a startup script that runs on startup for the Flutter container. I assume this is to launch/execute the Flutter application in a particular way. Did you include this in your setup?

Best Regards,
Jeremias

You don’t need to run with a docker compose on the target. You can manually the 2 docker containers you need - one with the weston compositor, and a second one with your flutter app.

Start weston with:

docker run -e ACCEPT_FSL_EULA=1 -d --rm --name=weston --net=host --cap-add CAP_SYS_TTY_CONFIG \
     -v /dev:/dev -v /tmp:/tmp -v /run/udev/:/run/udev/ \
     --device-cgroup-rule='c 4:* rmw' --device-cgroup-rule='c 13:* rmw' \
     --device-cgroup-rule='c 199:* rmw' --device-cgroup-rule='c 226:* rmw' \
     torizon/weston-vivante:$CT_TAG_WESTON_VIVANTE --developer weston-launch \
     --tty=/dev/tty7 --user=torizon

Then you can start your container. To do some debugging, you can just start it and enter it in on a bash shell and try running your flutter app by hand. I have a docker image with flutter I created on the imx8 (I can’t get a cross-compile to work) on docker hub. But I didn’t create it with a Dockerfile, I started with a docker image, and then ran a bunch of “apt” commands in the container, pulled in flutter-elinux, created a “hello_world” sample. Unfortunately, I can’t figure out exactly what I did. The docker container is on docker hub in Docker .

You can run it with

CONTAINER_CMD="/root/hello_world/build/elinux/arm64/release/bundle/hello_world -b /root/hello_world/build/elinux/arm64/release/bundle"

docker run -e ACCEPT_FSL_EULA=1 --rm -it --name=my-flutter-hello \
           -v /tmp:/tmp \
           -v /dev/dri:/dev/dri -v /dev/galcore:/dev/galcore \
           --device-cgroup-rule='c 199:* rmw' \
           --device-cgroup-rule='c 226:* rmw' \
           dawnhowesync/flutter-hello:firstbuild $CONTAINER_CMD

If you replace $CONTAINER_CMD with bash, you can poke around the container.
run with the command above, or:

cd ~/hello_world
export PATH=$PATH:/opt/flutter-elinux/bin
export PATH=$PATH:/opt/flutter-elinux/flutter/bin
flutter-elinux run

Reference: Debian Containers for Torizon | Toradex Developer Center

It seemed to be a bundle path issue, when putting it correctly as there, I get another error:

root@a80418ae5965:/app/gui# bundle/flutter_app -b $PWD/bundle
xdg_surface@16: error 3: xdg_surface has never been configured

With that being said, this might work for other people, and the approach described by @dawnhowe_alten works.

Essentially, I am now going in a different way. I am trying to achieve a workflow that is cleaner. So here’s my situation:

  1. On the x86 Host, activate Arm64 emulation
docker run --rm -it --privileged torizon/binfmt
  1. The following Dockerfile and the flutter_app/ folder (containing our flutter_app) are in the same directory:
####################################################################################################################
FROM --platform=linux/arm64/v8 arm64v8/ubuntu:20.04 AS bundle
ARG DEBIAN_FRONTEND=noninteractive

# Build environment dependencies for flutter-elinux
RUN apt-get -y update && apt-get install -y \
         build-essential clang cmake \
         curl git pkg-config \
         ninja-build unzip wget \
         libgtk2.0-dev libglib2.0-dev libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev \
         libegl1-mesa-dev libxkbcommon-dev libgles2-mesa-dev \
         libwayland-dev wayland-protocols
         
# Non root user
RUN groupadd -r -g 1441 flutter && useradd --no-log-init -r -u 1441 -g flutter -m flutter
USER flutter:flutter
WORKDIR /home/flutter

# Flutter 3.3.10 needs to be used (at this sha in particular) because 3.7 has this open issue: 
# https://github.com/flutter/flutter/issues/116703 (as of 07.03.2023)
RUN git clone https://github.com/sony/flutter-elinux.git &&\
    cd flutter-elinux &&\
    git reset --hard 19a1b05ea20675c36c705955c4148ad40b205161 &&\
    cd ..

# Add flutter-elinux to the path
ENV PATH="${PATH}:/home/flutter/flutter-elinux/bin"

# While not necessary, running flutter-elinux for the first time builds it
RUN flutter-elinux devices
RUN flutter-elinux doctor

# Add our application (folder in host context) and pass ownership of files to current user
RUN mkdir /home/flutter/flutter_app
COPY --chown=flutter flutter_app/* /home/flutter/flutter_app/

# Build our application
RUN cd flutter_app &&\
    flutter-elinux create . &&\
    flutter-elinux build elinux
    
####################################################################################################################
FROM --platform=linux/arm64/v8 torizon/debian:2-bullseye AS client

RUN apt-get -y update && apt-get install -y \
    clang cmake build-essential pkg-config libegl1-mesa-dev libxkbcommon-dev libgles2-mesa-dev \
    unzip git curl wget \
    libwayland-dev wayland-protocols \
    libdrm-dev libgbm-dev libinput-dev libudev-dev libsystemd-dev

# Tag 3316dd8728 corresponds to Flutter 3.3.10 which is used to create the bundle
RUN cd /opt &&\
    git clone --branch 3316dd8728 https://github.com/sony/flutter-embedded-linux.git &&\
    cd flutter-embedded-linux/ &&\
    mkdir build

# We need libflutter_engine.so (in release) to create flutter-client (in release too!)
RUN cd /opt/flutter-embedded-linux/ &&\
    wget https://github.com/sony/flutter-embedded-linux/releases/download/3316dd8728/elinux-arm64-release.zip &&\
    unzip elinux-arm64-release.zip -d elinux-arm64-release &&\
    rm elinux-arm64-release.zip &&\
    cp elinux-arm64-release/libflutter_engine.so build/

# Build the flutter wayland client in release form    
RUN cd /opt/flutter-embedded-linux/build &&\
    cmake -DUSER_PROJECT_PATH=examples/flutter-wayland-client -DCMAKE_BUILD_TYPE=Release .. &&\
    cmake --build .

###################################################################################################################
FROM --platform=linux/arm64/v8 torizon/weston-vivante:2 AS runtime
ARG IMAGE_ARCH

RUN mkdir -p /app/gui

RUN apt-get -y update && apt-get install -y \
         alsa-utils \
         psmisc \
         libgstreamer1.0-0 \
         gstreamer1.0-plugins-base \
         gstreamer1.0-plugins-good \
         gstreamer1.0-plugins-bad \
         gstreamer1.0-plugins-ugly \
         gstreamer1.0-libav \
         gstreamer1.0-doc \
         gstreamer1.0-tools \
         gstreamer1.0-x \
         gstreamer1.0-alsa \
         gstreamer1.0-gl \
         gstreamer1.0-gtk3 \
         gstreamer1.0-pulseaudio
         
COPY --from=bundle /home/flutter/flutter_app/build/elinux/arm64/release/bundle /app/gui/bundle
COPY --from=client /opt/flutter-embedded-linux/build/flutter-client /app/gui/flutter-client
COPY --from=client /opt/flutter-embedded-linux/build/libflutter_engine.so /lib/libflutter_engine.so

WORKDIR /app/gui/
ENV PATH="/app/gui:${PATH}"

ENTRYPOINT ["flutter-client"]
CMD [ "-f", "-b", "/app/gui/bundle"]
  1. Launch the build:
docker buildx build --platform=linux/arm64 -t flutter-demo:latest .
  1. This flutter-demo:latest image (you can explore it with docker run --rm -it --platform=linux/arm64 --entrypoint bash flutter-demo:latest), should contain the flutter_app bundle and the flutter-client executable.
  2. Send the image to the target (this could be through a docker registry technically):
    Host:
docker save flutter-demo:latest > ./flutter-demo.tar
scp flutter-demo.tar torizon@target.ip:/home/torizon
  1. Send the docker_compose_flutter.yaml as seen in the previous post to the target
  2. In the target, load the flutter demo docker image and launch docker compose:
docker load < flutter-demo.tar
docker stop $(docker ps -a -q)
docker-compose -f docker_compose_flutter.yaml up

Current situation

With the flutter-elinux create sample to have a flutter application instead of copying a “flutter_app” from the host context, this method worked. It isn’t perfect but at least it is reproducible as opposed to the blog.
However, I still have a rather weird issue. For some reason, my flutter_app when compiled gives me a bundle that then launches the sample application. I do not know exactly the reason for this.
A second issue is that with the flutter gallery application, the assets are not loading (except the black and white animation for the flutter logo on top)

If I understood correctly then it sounds like you were able to work a method out, albeit with some minor issues. In which case that is good to hear. Unfortunately there’s not much I can help out with in terms of the specifics of Flutter since that is not something we have too much expertise with.

For the Flutter specific questions/issues I would suggest maybe checking out the Flutter Github repository: GitHub - flutter/flutter: Flutter makes it easy and fast to build beautiful apps for mobile and beyond

Or we can try and put you in contact with Crossware.io who is our partner that authored the blog and demo.

Best Regards,
Jeremias

Jeremias,
Thanks for the support.

Unfortunately, I cannot recommend to our team to use Torizon until we can figure out a way to create a container in a CI pipeline, and this thread still hasn’t solved this. I am only able to create the container on the target and still need to figure out how to cross-compile everything on a dev machine. In addition, I need to figure out a dev workflow that allows development on a host machine using VsCode, which means that the functionality in the Toradex and Flutter extensions need to be merged. If these issues cannot be resolved, we will probably have to use a custom yocto build.

I have done much research in the flutter and flutter-elinux repos and have contacted Crossware.io. I did get an email a few weeks ago from Crossware.io indicating they would get back to me, but I have heard nothing since. The Toradex blog post this thread refers to does not display any of the comments I tried to make.

@dawnhowe_alten My last response was towards @mnano. I didn’t realize you had ongoing issues since you haven’t commented on this thread after our initial responses.

I am only able to create the container on the target and still need to figure out how to cross-compile everything on a dev machine.

Could you describe the issues with cross-compilation you are having? We have an article about cross-compiling with containers here: How to do C/C++ Development on Torizon | Toradex Developer Center

This article uses C/C++ as an example but the concepts should generically apply to anything that needs to be cross-compiled. Furthermore our VSCode IDE extensions more or less automate the setup of this. Though we currently do not have a project template for Flutter however.

As for the Flutter specific issues as I said this is not our expertise, but I can try and see if we can facilitate communication between you and Crossware.io.

All that said, maybe you can open a separate thread for this discussion since the thread here is diverging in different directions and it’s difficult to maintain 2 different conversations here at once.

Best Regards,
Jeremias

Thank you for the support.

We both have the same objective and problem, I think it fits this discussion.

I did some small progress in the time I had:

  • In the Dockerfile I posted last time, a small edit needs to be made for the copying of the flutter app in the bundle stage. I was essentially not properly copying the elements of the application previously (difference is flutter_app/* vs flutter_app/):
# Add our application (folder in host context) and pass ownership of files to current user
RUN mkdir /home/flutter/flutter_app
COPY --chown=flutter flutter_app /home/flutter/flutter_app/
  • I can compile most flutter application, granted they are compatible with flutter 3.3.10.
  • Most application can run either by calling the executable in the bundle folder or by using the flutter-client executable

As far as problems, for me, it lies in the proper use of plugins. The gallery application for example shows nothing in release, but in a Debug build, it shows the red errors typical of flutter. For my application, there is an issue with the proper loading of the video player plugin (I make it work with the bundle application but can’t with the flutter-client).

I would like to be connected to Crossware.io since their radio application in the blog uses gstreamer and a plugin that is probably similar to my flutter application. If we had access to their sources from that blog, everything would be solved. Seems to me like a simple solution.

Edit: Locales

I added this to the bundle and runtime stage:

# Set the locale (Add "apt-get install locales" as well!)
RUN sed -i '/en_US.UTF-8/s/^# //g' /etc/locale.gen && \
    locale-gen
ENV LANG en_US.UTF-8
ENV LANGUAGE en_US:en
ENV LC_ALL en_US.UTF-8

With locales, the gallery flutter application works perfectly!

My only remaining issue is gstreamer + flutter. Ideally we obtain Crossware.io code from the blog post.

@mnano I contacted our sales team in Europe and let them know about your request. They will reach out and see if they can facilitate contact between you and Crossware.io.

Best Regards,
Jeremias

Thank you for your help.

In the end, I have this Dockerfile:

####################################################################################################################
FROM --platform=linux/arm64/v8 arm64v8/ubuntu:20.04 AS build
ARG DEBIAN_FRONTEND=noninteractive

# Build environment dependencies for flutter-elinux
RUN apt-get -y update && apt-get install -y \
         build-essential clang cmake \
         curl git pkg-config \
         ninja-build unzip wget \
         libgtk2.0-dev libglib2.0-dev libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev \
         libegl1-mesa-dev libxkbcommon-dev libgles2-mesa-dev \
         libwayland-dev wayland-protocols \
         locales

# Set the locale
RUN sed -i '/en_US.UTF-8/s/^# //g' /etc/locale.gen && \
    locale-gen
ENV LANG en_US.UTF-8
ENV LANGUAGE en_US:en
ENV LC_ALL en_US.UTF-8

# Non root user
RUN groupadd -r -g 1441 flutter && useradd --no-log-init -r -u 1441 -g flutter -m flutter
USER flutter:flutter
WORKDIR /home/flutter

# Flutter 3.3.10 needs to be used (at this sha in particular) because 3.7 has this open issue:
# https://github.com/flutter/flutter/issues/116703 (as of 07.03.2023)
RUN git clone https://github.com/sony/flutter-elinux.git &&\
    cd flutter-elinux &&\
    git reset --hard 19a1b05ea20675c36c705955c4148ad40b205161 &&\
    cd ..
   
# Add flutter-elinux to the path
ENV PATH="${PATH}:/home/flutter/flutter-elinux/bin"

# While not necessary, running flutter-elinux for the first time builds it
RUN flutter-elinux devices
RUN flutter-elinux doctor

# Add our application (folder in host context) and pass ownership of files to current user
RUN mkdir /home/flutter/flutter_app
COPY --chown=flutter my_local_flutter_app /home/flutter/flutter_app/

# Get the Gallery Application
RUN cd flutter_app &&\
    flutter-elinux create . &&\
    flutter-elinux upgrade && flutter-elinux clean && flutter-elinux pub get &&\
    flutter-elinux build elinux

###################################################################################################################
FROM --platform=linux/arm64/v8 torizon/weston-vivante:2 AS runtime
ARG IMAGE_ARCH

RUN mkdir -p /app/gui

RUN apt-get -y update && apt-get install -y \
         alsa-utils \
         libasound2 \
         psmisc \
         procps pciutils \
         libgstreamer1.0-0 \
	 gstreamer1.0-plugins-base \
	 gstreamer1.0-plugins-good \
	 gstreamer1.0-plugins-bad \
	 gstreamer1.0-plugins-ugly \
	 gstreamer1.0-libav \
	 gstreamer1.0-doc \
	 gstreamer1.0-tools \
	 gstreamer1.0-x \
	 gstreamer1.0-alsa \
	 gstreamer1.0-gl \
         gstreamer1.0-gtk3 \
	 gstreamer1.0-pulseaudio \
         v4l-utils \
         locales

# Set the locale
RUN sed -i '/en_US.UTF-8/s/^# //g' /etc/locale.gen && \
    locale-gen
ENV LANG en_US.UTF-8
ENV LANGUAGE en_US:en
ENV LC_ALL en_US.UTF-8

# Get the flutter bundle built in the build environment
COPY --from=build /home/flutter/flutter_app/build/elinux/arm64/release/bundle /app/gui/bundle

# The .so libraries (notably libflutter_engine.so) must be in the library path
# to properly execute the flutter_app. Some plugin (like the elinux video_player plugin)
# also generate a .so library, and NEED to be in the library path.
COPY --from=build /home/flutter/flutter_app/build/elinux/arm64/release/bundle/lib /lib/

WORKDIR /app/gui/bundle/
ENV PATH="/app/gui:${PATH}"

ENTRYPOINT ["./flutter_app"]
CMD [ "-f", "-b", "../bundle/"]

note: some packages/steps might not be necessary, so this can be cleaned up further

This should work for a good amount of Flutter application in a docker container on an iMX8 running TorizonCore (I tested the Flutter Gallery successfully). The steps to use this are the same as in my previous post.

My problem now requires another post I believe and seems purely related to gstreamer:

  • The sony video player plugin does not load in my flutter app before I call gstreamer at least once
  • I cannot get audio to work at all, even following How to play audio on TorizonCore using Alsa and C/C++ | Toradex Developer Center → You have to pass --device /dev/snd to the docker container (with compose or as a docker run flag)
  • How to implement the NXP’s gstreamer plugins (such as imxvideoconvert_g2d) in a TorizonCore docker container?
1 Like

@mnano I saw you opened separate threads for your follow up questions. We’ll break off the conversations into those threads to keep things orderly.