工控網首頁
>

應用設計

>

在嵌入式 Linux 設備上使用 Flutter 開發圖形界面

在嵌入式 Linux 設備上使用 Flutter 開發圖形界面

在嵌入式設備上開發圖形用戶界面通常會選擇 Qt。這是一種經驗證的方案,我們可以在多個領域看到用 Qt 開發的 UI。但隨著移動端和 web 端界面更為廣泛地使用,源自于這兩個領域的技術也開始向嵌入式設備滲透。Flutter 就是一個例子。本文將介紹如何在 Torizon 平臺上如何使用 Flutter 來開發用戶界面。

 

Google 面向 Android, iOS 推出的跨平臺移動應?開發框架 Flutter 可以構建高質量的原??戶界?并可以擴展支持 Web 和桌面應用。Flutter 尚未官方支持嵌入式系統但目前 Sony  Ubuntu 正在致力于該工作。例如來自 Sony  elinux 可以在嵌入式平臺上使用 Flutter。我們也將以此為基礎 Verdin iMX8M Plus  Torizon 上運行 Flutter 應用。

 

我們來看看 Flutter 的構架。如下圖所示其由三個部分構成User app, Framework  Engineflutter-elinux-linux 屬于為嵌入式提供支持的 embbedder。它可以運行在 wayland 顯示后臺這也是 Torizon 提供的顯示框架。flutter-elinux-linux 將提供 flutter-client libflutter_elinux_wayland.so  libflutter_engine.so。這些軟件的功能參考該網頁描述。

在嵌入式 Linux 設備上使用 Flutter 開發圖形界面_web966.png 

https://github.com/sony/flutter-embedded-linux/wiki/Features-of-Embedded-Linux-embedding-for-Flutter

 

flutter-elinux  Flutter SDK 的一個非官方插件用于為嵌入式設備創建、編譯和調試 Flutter 應用并使用 flutter-elinux-linux 在設備上顯示。

 

為了減少對編譯電腦的軟件環境影響我們將使用 docker 容器進行編譯。使用下面命令獲取 ubuntu:20.04 容器并進入其中。由于后面需要向容器內提供文件這里將 /home/user/flutter 映射到容器內的 /opt/flutter

-----------------------------------------------

~$ docker pull ubuntu:20.04

~$ docker run -it -v /home/user/flutter:/opt/flutter --name flutter_build ubuntu:20.04 /bin/bash

-----------------------------------------------

 

如果后續進入該容器重新編譯,可以使用下面命令:

-----------------------------------------------

~$ docker container start flutter_build

~$ docker exec -it flutter_build bash

-----------------------------------------------

 

在容器中安裝所需的軟件。

-----------------------------------------------

# apt update

# apt upgrade

# apt install clang cmake build-essential pkg-config libegl1-mesa-dev libxkbcommon-dev libgles2-mesa-dev

# apt install libwayland-dev wayland-protocols git curl wget unzip git

# apt install python2

# apt install virtualenv

-----------------------------------------------

 

下載編譯工具。

-----------------------------------------------

# mkdir -p /opt/flutter

# cd /opt/flutter

# git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git

# export PATH=$PATH:$(pwd)/depot_tools

-----------------------------------------------

 

默認的 ubuntu:20.04 使用 Python3,在容器里使用 virtualenv 創建 Python2 環境。

-----------------------------------------------

# virtualenv .env -p python2

# source .env/bin/activate

-----------------------------------------------

 

創建 .gclient 文件并指定版本。

-----------------------------------------------

# cat .gclient

solutions = [

{

  "managed": False,

  "name": "src/flutter",

  "url": "https://github.com/flutter/engine.git@bd539267b42051b0da3d16ffa8f48949dce8aa8f",

  "custom_deps": {},

  "deps_file": "DEPS",

  "safesync_url": "",

  "custom_vars" : {

    "download_android_deps" : False,

    "download_windows_deps" : False,

  },

},

]

-----------------------------------------------

 

上面的 bd539267b42051b0da3d16ffa8f48949dce8aa8f 對應 ${path_to_flutter_sdk_install}/flutter/bin/internal/engine.version,兩者需要一致。如果不指定的話,會下載最新的版本。除非確實需要編譯最新版本的 Engine,否則并不推薦。

獲取代碼。

-----------------------------------------------

# gclient sync

-----------------------------------------------

 

編譯 embbedder。這里編譯為 arm64 目標 release 模式的 embedder

-----------------------------------------------

# cd src

# ./flutter/tools/gn --target-os linux --linux-cpu arm64 --runtime-mode release --embedder-for-target --disable-desktop-embeddings --no-build-embedder-examples

# ninja -C out/linux_release_arm64

-----------------------------------------------

 

編譯成功后在 out/linux_release_arm64 目錄中可以看到 libflutter_engine.so 文件。

 

接下來將編譯 Embedded Linux embedding for Flutter,這里會生成 flutter-client 和 libflutter_elinux_wayland.so。如果在 X86 電腦上交叉編譯需要使用 Yocoto Project 生成包含 clang 在內的 SDK這會涉及大量的工作內容。在 Torizon 中我們可以直接使用 debian 容器并通過 apt 命令安裝相應的軟件 Verdin iMX8M Plus 本地編譯。這通常適用于代碼量不是很多的項目。在 Verdin iMX8M Plus 上運行下面命令啟動 debian 容器。

-----------------------------------------------

~$ docker run -it  -v /home/torizon/workspace:/opt/workspace torizon/debian:$CT_TAG_DEBIAN /bin/bash

-----------------------------------------------

 

在容器中安裝所需的軟件。

-----------------------------------------------

# apt update

# apt install clang cmake build-essential pkg-config libegl1-mesa-dev libxkbcommon-dev libgles2-mesa-dev

# apt install unzip git

# apt install curl wget

# apt install libwayland-dev wayland-protocols

# apt install libdrm-dev libgbm-dev libinput-dev libudev-dev libsystemd-dev

# cd /opt/workspace

-----------------------------------------------

 

下載 flutter-embedded-linux 代碼。

-----------------------------------------------

# git clone https://github.com/sony/flutter-embedded-linux.git

# cd flutter-embedded-linux/

# mkdir build

-----------------------------------------------

 

此時將剛才編譯的 libflutter_engine.so 復制到 build 目錄。然后分別執行下面兩個命令。

-----------------------------------------------

# cmake -DUSER_PROJECT_PATH=examples/flutter-wayland-client -DCMAKE_BUILD_TYPE=Release ..

 

# cmake -DUSER_PROJECT_PATH=examples/flutter-wayland-client -DCMAKE_BUILD_TYPE=Release -DBUILD_ELINUX_SO=ON -DBACKEND_TYPE=WAYLAND -DENABLE_ELINUX_EMBEDDER_LOG=OFF -DFLUTTER_RELEASE=ON ..

-----------------------------------------------

 

編譯完成后在 build 目錄下可以看到生成的 flutter-client 和 libflutter_elinux_wayland.so 兩個文件。上面使用的編譯選項含義請參考該網頁說明。

 

接下來重新回到 X86 編譯電腦開始 Flutter 應用的編譯。用下面命令重新進入使之前的 ubuntu:20.04 容器。

-----------------------------------------------

~$ docker exec -it flutter_build bash

-----------------------------------------------

 

 

下載 flutter-elinux。這個是 Flutter SDK

-----------------------------------------------

# cd /opt/flutter/

# git clone https://github.com/sony/flutter-elinux

# export PATH=$PATH:/opt/flutter/flutter-elinux/bin

-----------------------------------------------

 

運行下面命令查看安裝情況。

-----------------------------------------------

# flutter-elinux doctor

# flutter-elinux devices

-----------------------------------------------

 

創建一個示例工程。

-----------------------------------------------

# flutter-elinux create demo1

# cd demo1

-----------------------------------------------

 

按照這里的說明交叉編譯創建的工程。但在這之前需要準備 Verdin iMX8M Plus  arm64 格式文件系統。該文件系統可以是來自剛才在 Verdin iMX8M Plus 上編譯 Embedded Linux embedding for Flutter 的容器。

 

 Verdin iMX8M Plus 運行下面命令查看容器 ID

-----------------------------------------------

$ docker ps -a

CONTAINER ID        IMAGE                       COMMAND             CREATED             STATUS                     PORTS               NAMES

3dea07245b24        torizon/debian:2-bullseye   "/bin/bash"         2 days ago          Exited (137) 2 hours ago                       hardcore_nightingale

-----------------------------------------------

 

將容器的文件系統復制出來并打包。

-----------------------------------------------

$ sudo docker cp 3dea07245b24:/ arm64-sysroot

$ sudo tar cvf arm64-sysroot.tar arm64-sysroot

-----------------------------------------------

 

然后將 arm64-sysroot.tar 復制到 X86 編譯電腦的 flutter_build 容器中,位于 /opt/flutter 目錄。回到 flutter_build 容器,解壓 arm64-sysroot.tar

-----------------------------------------------

# cd /opt/flutter/

# tar vxf arm64-sysroot.tar

-----------------------------------------------

 

進入剛才創建的 demo1 目錄,運行下面命令編譯。

-----------------------------------------------

# cd demo1

# flutter-elinux build elinux --target-arch=arm64 --target-sysroot=/opt/flutter/arm64-sysroot

-----------------------------------------------

 

待編譯結束后,查看 build/elinux/arm64/release/bundle,這里是 Flutter app 運行所需的所以文件。

-----------------------------------------------

# tree build/elinux/arm64/release/bundle -L 2

.

|-- data

|   |-- flutter_assets

|   `-- icudtl.dat

|-- demo1

`-- lib

  |-- libapp.so

  |-- libflutter_elinux_wayland.so

  `-- libflutter_engine.so

-----------------------------------------------

 

libflutter_elinux_wayland.so 和 libflutter_engine.so 是 Fltter SDK 預編譯的庫文件,需要將其替換為之前編譯的庫文件。

 

將 flutter-client 和 bundle 文件夾復制到 Verdin iMX8M Plus 的 /home/torizon/flutter_demo 目錄。然后先啟動 weston 容器。

-----------------------------------------------

$ 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

-----------------------------------------------

 

再啟動另外一個 torizon/weston-vivante 容器,在里面我們將用命令行的方式啟動編譯好的 demo1

-----------------------------------------------

$ docker run -e ACCEPT_FSL_EULA=1 -it --rm --name=wayland-app --user=torizon \

           -v /dev/dri:/dev/dri -v /dev/galcore:/dev/galcore -v /tmp:/tmp -v /home/torizon/flutter_demo:/opt/flutter \

           --device-cgroup-rule='c 199:* rmw' --device-cgroup-rule='c 226:* rmw' \

           torizon/weston-vivante:$CT_TAG_WESTON_VIVANTE bash

-----------------------------------------------

 

在啟動的容器內運行下面命令。

-----------------------------------------------

# cd /opt/flutter

# LD_LIBRARY_PATH=/opt/flutter/bundle/lib/ ./flutter-client -b /opt/flutter/bundle

-----------------------------------------------

 

 

在嵌入式 Linux 設備上使用 Flutter 開發圖形界面_web9412.png 

 

 

最后,我們將介紹如何導入一個現成的 Flutter 項目并打包為一個容器,用 docker-compose 文件啟動。這里以 covid19_mobile_app 為例進行說明。

 

在 flutter_build 容器中,下載 covid19_mobile_app 代碼,將之前 demo1 目錄中的 elinux 文件夾復制到 covid19_mobile_app 后再編譯。同樣libflutter_elinux_wayland.so  libflutter_engine.so 也需要替換為之前編譯的庫文件。

-----------------------------------------------

# cp -r ../demo1/elinux covid19_mobile_app

# flutter-elinux pub get

# flutter-elinux build elinux --target-arch=arm64 --target-sysroot=/opt/flutter/arm64-sysroot

-----------------------------------------------

 

編譯結束后,將 covid19_mobile_app 的 bundle 目錄連同 flutter-client,以及下面的 startup.shDockerfile 放到任一目錄中。

 

startup.sh

-----------------------------------------------

#!/bin/bash

LD_LIBRARY_PATH=/home/torizon/bundle/lib/ /usr/sbin/flutter-client -b /home/torizon/bundle

-----------------------------------------------

 

Dockerfile

-----------------------------------------------

FROM --platform=linux/arm64 torizon/weston-vivante:2

ADD bundle /home/torizon/bundle

COPY flutter-client /usr/sbin

COPY startup.sh /home/torizon

CMD [ "/home/torizon/startup.sh" ]

-----------------------------------------------

 

運行下面命令生成一個 flutter app 容器。

-----------------------------------------------

$ docker build -t flutter_demo:1 .

-----------------------------------------------

 

將 flutter_demo:1 容器和 docker-compose.yml 文件復制到 Verdin iMX8M Plus 上。

 

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'

-----------------------------------------------

 

運行 docker-compose up -d 即可啟動 weston 和 flutter app 容器。

在嵌入式 Linux 設備上使用 Flutter 開發圖形界面_web11680.png 

 

 

 

總結

Flutter 框架為圖形界面開發提供一個非常靈活的方案,使得嵌入式開發也可以從中受益。于此同時,嵌入式 Linux 對 Flutter 的支持也處于早期階段,項目開發需要充分驗證。


審核編輯(
王靜
)
投訴建議

評論

查看更多評論
其他資訊

查看更多

TorizonQt容器中文顯示

IoT 安全系列博文第三篇 軟件更新安全:常見的錯誤

IoT 安全系列博文第二篇: 遠程更新的危險

為什么我們需要遠程自動更新互聯設備?

基于NXP iMX6ULL 擴展音頻解碼器 MAX98357A