Blog:
Flutter 在嵌入式 Linux 的应用

Friday, January 19, 2024

简介

在嵌入式 Linux 设备上常使用 Qt 作为开发图形界面应用的框架,随着 web 和移动端图形框架技术快速发展,嵌入式 Linux 也可以从这些技术中受益。由 Google 开发的 Flutter 最初用于 Android iOS 应用开发,后期加入 webWindwos 桌面和 Linux 桌面的支持。配合适当的渲染引擎, Flutter 也可以运行在嵌入式 Linux 设备上。文章将介绍如何在使用 Linux BSP Verdin iMX8M Plus 上运行 Flutter 应用。


硬件介绍

本次演示使用基于 NXP iMX8M Plus SoC 的计算机模块 Verdin iMX8M Plus。底板为 Dahlia,该底板可以直接使用 Verdin iMX8M Plus 的 HDMI 显示输出。屏幕则使用支持电容屏的 HDMI 显示器,用于测试 Flutter 应用的交互性。


Flutter 介绍

Flutter 使用 Dart 语言开发,可以跨平台运行,支持 AOTAhead of time)预编译,使应用在设备上更高效地运行。对于 Flutter 应用,用户通常只需要开发 apps 代码, FrameworkEngine Embedder都油 Flutter SDK 提供。使用不同的 embedderFlutter app 可以运行在不同的平台上。目前官方支持embedder 包括 AndroidiOSMacOSWindwos 桌面、 Linux 桌面、 Web 浏览器

Linux 桌面需要依赖 GTK X11,现在的嵌入式 Linux 系统已经普遍使用 Wayland,例如 NXP iMX 处理器在新的 BSP 已经不再支持 X11。对于嵌入式 Linux 系统,可以使用下面两个非官方的 embedder

  • Flutter-elinux,这是由 Sony 维护的项目,支持 Arm64 和 X64 处理器。可以使用 Wayland 或者 X11 后台,或者直接基于 DRM。

  • Flutter-pi是针对树莓派开发和优化的 embbeder,其不依赖于 X11 和 GTK 的任何组件。支持 KMS 和 DRI,3D 硬件加速。可以运行在 ARMv7、ARMv8、x86 处理器上。Flutter-pi 拥有更活跃的社区和开发者。结合flutterpi_tool工具可以非常容易地开发 flutter 应用。

Verdin iMX8M Plus 的 Linux BSP 支持 KMS,其 CPU 也是 Armv8 架构。因此,我们本次选用 Flutter-pi 作为 embedder。关于 Flutter-elinux 在 Toradex 模块上的应用,可以参考该文章


添加 meta-flutter

meta-flutter提供了编译 flutter-pi 以及 flutter demo 的文件。meta-flutter 依赖 meta-clang layer。Toradex Linux BSP v6 基于 Yocto Project 的 kirkstone 分支。首先,参考这里创建 Yocto Project 编译环境。然后进入 layers 文件夹,下载 meta-flutter 和 meta-clang。

$ git clone --branch kirkstone https://github.com/meta-flutter/meta-flutter.git
$ git clone --branch kirkstone https://github.com/kraj/meta-clang.git


然后在 build/conf/bblayers.conf 文件的 BBLAYERS 中添加 meta-flutter 和 meta-clang 的路径。

BBLAYERS ?= " \
${BBLAYERS_NXP} \
...
${TOPDIR}/../layers/meta-clang \
${TOPDIR}/../layerss/meta-flutter \
"


在 build/conf/local.conf 文件的结尾添加以下内容。

DEFAULT_TIMEZONE = "Asia/Shanghai"
ENABLE_BINARY_LOCALE_GENERATION = "1"
IMAGE_LINGUAS:append = " en-us en-gb es-us zh-cn"
GLIBC_GENERATE_LOCALES:append = " en_US.UTF-8 es_US.UTF-8 en_GB.UTF-8 zh_CN.UTF-8"
IMAGE_INSTALL:append = " tzdata-core tzdata-asia"
DISTRO_FEATURES:append = " opengl wayland pam"
PACKAGECONFIG:append:pn-weston = " remoting"
PACKAGECONFIG:append:pn-flutter-engine = " profile debug"
IMAGE_INSTALL:append = " flutter-auto packagegroup-flutter-test-apps \
flutter-pi flutter-gallery"
IMAGE_INSTALL:remove = " packagegroup-tdx-qt5"


删除 meta-flutter/recipes-platform/packagegroups/ packagegroup-flutter-test-apps.bb 中的 flutter-test-texture-egl。最后编译 tdx-reference-multimedia-image 镜像文件。

$ bitbake tdx-reference-multimedia-image


测试 Flutter 应用

禁用自启动的 weston 服务。

root@verdin-imx8mp:~# systemctl stop weston.service
root@verdin-imx8mp:~# systemctl disable weston.service


镜像中的 /usr/share/flutter/gallery/3.16.5/release 中已经包含一个 flutter gallery 应用,现在可以使用 flutter-pi 直接运行。

root@verdin-imx8mp:# cd /usr/share/flutter/gallery/3.16.5/release
root@verdin-imx8mp:# flutter-pi --release ./


在 HDMI 显示器上可以看到 gallery 应用的界面。


安装 Flutter SDK 和 flutterpi_tool

在 Linux 电脑(例如 Ubuntu 23.04)上,首先安装 Flutter SDK。由于 Flutter 和 flutter-pi 两个项目更新都比较活跃,在安装前需求确认 Flutter 版本。在这里查看 flutter-pi 目前使用的 Flutter 版本。例如撰写文章时其为 3.16.7。在 Flutter SDK 手动安装页面选择对应的版本进行安装,如 flutter_linux_3.16.7-stable.tar.xz。

$ sudo apt-get install clang cmake git ninja-build \
pkg-config libgtk-3-dev liblzma-dev libstdc++-12-dev
$ cd FLUTTER_SDK_INSTALL_PATH
$ tar vxf flutter_linux_3.16.7-stable.tar.xz
$ export PATH="$PATH:`pwd`/flutter/bin"
$ flutter doctor -v


上面的 flutter 环境诊断工具如果提示缺少 chrome 浏览器,可以安装后再运行。

$ sudo dpkg -i google-chrome-stable_current_amd64.deb
$ flutter doctor -v


检查 flutter 和 dart 命令是否都来自同一个的 SDK 安装目录。

$ which flutter dart
/home/ben/flutter-sdk/flutter/bin/flutter
/home/ben/flutter-sdk/flutter/bin/dart


安装完 Flutter SDK 后使用下面命令安装 flutterpi_tool

$ flutter pub global activate flutterpi_tool
$ export PATH="$PATH":"$HOME/.pub-cache/bin"


使用下面命令测试

$ flutterpi_tool --help


如果已经安装好 Flutter SDK 和 flutterpi_tool,需要编译其他 flutter 应用时,只需要进入之前 Flutter SDK 的安装目录后执行下面命令,重新配置编译环境即可。

$ cd FLUTTER_SDK_INSTALL_PATH
$ export PATH="$PATH:`pwd`/flutter/bin"
$ export PATH="$PATH":"$HOME/.pub-cache/bin"


使用 flutterpi_tool 编译应用

借助 flutterpi_tool 可以非常简单的编译 flutter 应用,例如针对 64 位 Arm CPU 的编译命令 flutterpi_tool build --arch=arm64 --cpu=pi4 --release,参数说明如下:

参数
说明
Runtime mode
--debug Build for debug mode.
--profile Build for profile mode.
--release Build for release mode.
--debug-unoptimized Build for debug mode and use unoptimized engine. (For stepping throughengine code)
Target, --arch=
arm Build for 32-bit ARM. (armv7-linux-gnueabihf)
arm64 Build for 64-bit ARM. (aarch64-linux-gnu)
x64 Build for x86-64. (x86_64-linux-gnu)
Target, --cpu=
generic (default) Don’t use a tuned engine. The generic engine will work on all CPUs of the specified architecture.
pi3 Use a Raspberry Pi 3 tuned engine. Compatible with arm and arm64. (-mcpu=cortex-a53+nocrypto -mtune=cortex-a53)
pi4 Use a Raspberry Pi 4 tuned engine. Compatible with arm and arm64. (-mcpu=cortex-a72+nocrypto -mtune=cortex-a72)


下面是在 Linux 电脑上编译 flutter gallery 应用。由于 Verdin iMX8M Plus 是基于 arm64 Cortex-A53 CPU,因此选择 --arch=arm64 --cpu=pi3 两个参数。

$ git clone https://github.com/flutter/gallery.git flutter_gallery
$ cd flutter_gallery/
$ git checkout 6a8d738c94d0710e229d726729c09fdb5ccaf7ed
$ flutter pub get
$ flutterpi_tool build --arch=arm64 --cpu=pi3 --release


编译结束后,在 build/flutter_assets 目录下可以看到如下文件。
build/flutter_assets/
├── app.so
├── AssetManifest.bin
├── AssetManifest.json
├── FontManifest.json
├── fonts
├── icudtl.dat
├── libflutter_engine.so
├── NOTICES.Z
├── packages
└── shaders


flutteri_tool 目前使用新的编译方法生成的文件结构尚不能直接使用 flutter_pi 在设备上直接运行,需要重新调整文件位置,参考 Verdin iMX8M Plus 上的 /usr/share/flutter/gallery/3.16.5/release 的内容。

release/
├── data
│   ├── flutter_assets
│   └── icudtl.dat
└── lib
  ├── libapp.so
  └── libflutter_engine.so


在 flutter_gallery/build/flutter_assets/ 目录创建 data 和 lib 两个文件夹,app.so 重命名为 libapp.so 后和 libflutter_engine.so 一起移动到 lib 目录。icudtl.dat 移动到 data 目录下。在 data 目录下创建 flutter_assets 文件夹后,将 build/flutter_assets/ 中剩余的 AssetManifest.bin,AssetManifest.json,FontManifest.json,fonts,NOTICES.Z,packages 和 shaders 均移动到 data/flutter_assets 中。完场后将 data 和 lib 两个目录复制到 Verdin iMX8M Plus 上的 /home/root/flutter_gallery 目录中,例如使用 scp 命令。

$ scp -r build/flutter_assets/ root@imx8mp_ip:/home/root/flutter_gallery


复制好文件后可以在 Verdin iMX8M Plus 上的 /home/root/flutter_gallery 看到以下内容。

root@verdin-imx8mp-07320826:~/flutter_gallery# ls *
data:
flutter_assets  icudtl.dat

lib:
libapp.so  libflutter_engine.so


运行下面命令即可启动在电脑上编译的 flutter 应用。

root@verdin-imx8mp:~#  flutter-pi --release /home/root/flutter_gallery/


总结

使用 Flutter 可以开发跨平台应用,并获得流畅的本地运行体验,在移动端和 Web 端都有广泛的应用。但是针对嵌入式 Linux 的 embedder 目前是第三方维护的,所以在实际应用时需要做详尽的测试。

Author: 胡珊逢,FAE,韬睿(上海)
Share this on:

Leave a comment

Please login to leave a comment!
Have a Question?