Flutter 在嵌入式 Linux 的应用
- 关键词:ARM,Linux,NXP
- 作者:By Toradex胡珊逢
- 摘要:在嵌入式 Linux 设备上常使用 Qt 作为开发图形界面应用的框架,随着 web 和移动端图形框架技术快速发展,嵌入式 Linux 也可以从这些技术中受益。由 Google 开发的 Flutter 最初用于 Android 和 iOS 应用开发,后期加入 web、 Windwos 桌面和 Linux 桌面的支持。配合适当的渲染引擎, Flutter 也可以运行在嵌入式 Linux 设备上。文章将介绍如何在使用 Linux BSP 的 Verdin iMX8M Plus 上运行 Flutter 应用。
简介
在嵌入式 Linux 设备上常使用 Qt 作为开发图形界面应用的框架,随着 web 和移动端图形框架技术快速发展,嵌入式 Linux 也可以从这些技术中受益。由 Google 开发的 Flutter 最初用于 Android 和 iOS 应用开发,后期加入 web、 Windwos 桌面和 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 语言开发,可以跨平台运行,支持 AOT(Ahead of time)预编译,使应用在设备上更高效地运行。对于 Flutter 应用,用户通常只需要开发 apps 代码, Framework、 Engine 和 Embedder都油 Flutter SDK 提供。使用不同的 embedder, Flutter app 可以运行在不同的平台上。目前官方支持embedder 包括 Android, iOS, MacOS、 Windwos 桌面、 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 目前是第三方维护的,所以在实际应用时需要做详尽的测试。