Showing Posts From
Flutter
- 27 Apr, 2026
总结Android Flutter项目中YOLO模型的执行流程
之前基于 Flutter 实现了一个在Android APP中调用YOLO模型来实现图像目标检测功能,本文的 YOLO 模型的 TFLite 导出以及在 Android Flutter 项目中进行调用的完整执行流程进行总结。 在Android上跑AI模型,标准的做法是导出模型文件为 TFLite 格式,然后在 Android 的 TFLite+Interpreter+NCAPI 框架下执行AI模型的推理流程,与该框架相关的知识可参考 如何理解TFLite/LiteRT的核心概念和框架流程?一文。 YOLO模型的TFLite导出 因为 Ultralytics 项目中的模型导出的实现已经非常完备,所以可以直接在ultralytics项目中通过其export接口导出 tflite 模型文件即可,此处选择导出为half即float16的格式: 此外,后续在Flutter项目中调用以上模型文件进行推理,还需要创建一个与模型对应的label.txt文件,其中包含有模型检出类别对应的类别名称字符串,按顺序每行一个。因为我测试中直接使用的是YOLO的预训练pt文件,预训练模型文件对应的是COCO数据集,所以这里的label.txt中包含的类别名称字符串大致就是如下80个类别: 依赖管理 因为要在 Android Flutter APP 增加跑AI模型的的能力,首先需要在项目根目录下的pubspec.yaml和 android/app 目录下的build.gradle.kts增加相关的依赖项。 flutter项目中的pubspec.yaml是该项目的元数据中心(Metadata Center)和依赖管理器(Dependency Manager)。其中包含的主要内容是:项目的基本配置信息,生产环境的依赖库,开发/测试阶段的依赖库,资源与资产等。对于以上提到的依赖项,每次在构建项目时,都会自动调用 flutter pub get 从pub.dev下载指定依赖库的源代码到本地。 该项目中需要对手机camera和本地图片的图像调用YOLO模型进行检测,所以pubspec.yaml中相关的设置项包括: 因此,对于在 Android 项目中跑YOLO模型而言,以上配置文件最关键的就是其中导入了 flutter_vision 这个插件。该插件内置了 TensorFlow Lite C SDK,并针对 YOLO 这种特定模型,包含了输入输出的 ByteBuffer、维度转换(Tensor Shape)和 NMS(非极大值抑制)等的相关处理,对于应用层程序而言,只需要调用 vision.loadYoloModel() 接口,它就可以在 Android 原生层创建 TFLite 的 Interpreter并执行推理任务。 模型在Flutter中的完整推理流程 与其他板端模型的完整推理流程类似,在Android Flutter项目中调用YOLO模型执行推理任务同样包含模型加载、前向推理以及后处理这三个环节。 模型加载 基于flutter_vision插件对AI模型进行加载的整体流程如下: 整体的模型加载过程很简单,调用flutter_vision的loadYoloModel接口创建一个模型加载的异步任务,传递模型文件和label文件等参数,然后等待这个异步任务执行完成即可。 需要注意的是,flutter_vision 插件只能够支持ultralytics项目export接口直接以tflite格式导出的YOLOv5,YOLOv8,YOLOv11这几个模型,而且参数中指定的模型文件与modelVersion的参数必须设置正确,否则后续的后处理流程会出错: !074e2e0e-d2b9-48e6-b0b2-4a1f06769c23.png 那么如果我们要在 Android APP 中跑其他模型呢?那就只能使用 tflite_v2 插件、flutter_tflite插件或者底层 TensorFlow Lite API。 前向推理和后处理 flutter_vision插件的前向推理过程主要就是调用其yoloOnFrame(针对摄像头的图像)和yoloOnImage接口(针对本地图片)。 以上的推理接口执行中本身已经包含了YOLO不同版本的后处理流程,所以其输出结果是一个的数组。这个数组中的每一项都对应于一个最终检测框的类比和坐标+置信度,如下所示: 应用层拿到以上的这个数组以后,就可以对其中的内容进行解析并在图像上画框标注了。因为 yoloOnFrame 和 yoloOnImage 接口中已经包含了后处理的NMS等环节,所以不需要在应用层再执行后处理了。 参考资料 - flutter_vision | Flutter package
- 01 Apr, 2026
在Android Flutter项目中flutter_litert插件运行TFLite模型
在之前的一篇笔记(总结Android Flutter项目中YOLO模型的执行流程)中,我详细总结了基于flutter_vision插件在一个Android Flutter项目中把Ultralytics项目中导出的YOLOv8模型运行起来的完整流程。 但是Flutter_Vision插件的使用有诸多限制,例如只能运行YOLO的几个模型,并且只能配合Ultralytics的export接口导出的TFLite模型文件来使用。那么如果想要在Android上跑YOLO之外的模型,就没有办法是用Flutter_Vision插件了。 因此,要把一个自定义的模型转换为TFLite格式并且能够在Android APP中跑起来,就需要一个更灵活的应对方式。而这个过程分为两个步骤: - 把自定义模型的pt文件转换为TFLite格式。这部分在如何把PT格式的模型转换为TFLite/LiteRT模型?已有详细总结。 - 把以上转换的TFLite格式的模型文件在Android Flutter项目中跑起来,避免受到FlutterVision插件所带来的限制。这一点就是本文要解决的问题。 flutter_litert vs tflite_flutter 在Android Flutter项目中跑 TFLite模型,目前比较常用的是flutter_litert和tflite_flutter这两个插件。 - tflite_flutter:这个插件是 Flutter 社区中最经典、最老牌的 TFLite 插件,目前搜到的信息大部分都是使用这个插件在Android上跑AI模型。它通过 Dart FFI 直接封装了 C 语言的 TFLite 解释器。目前仍有社区维护版(如tflite_flutter_plus),但配置分散,社区维护分散,在新的项目中不建议使用。 - flutter_litert:这个插件是为了响应 Google 对 TensorFlow Lite 品牌的正式更名和升级 (LiteRT) 而推出的现代继任者。它也是目前推荐的、更符合 Google 最新人工智能路线图的插件,其本质上是 tflite_flutter 的演进版本,旨在解决旧插件的维护痛点。因此强烈建议在新的项目中使用flutter_litert这个插件。 !image.png flutter_litert 这个插件本质上就是一个工作在 Flutter(Dart 语言)层级的硬件抽象层 (HAL) Wrapper。这个插件总的特点是: - 底层机制: 该插件并不是用 Dart 重写模型的推理逻辑,而是通过 Dart FFI (Foreign Function Interface) 接口极其轻量地绑定了 Google 已经预编译好的 C++ LiteRT Native 二进制库(.so 文件),这样的好处当然是可以利用底层的C/C++语言的执行达到最高的效率。 - 零拷贝理念: 其核心思想是在内存里开辟一段连续的 Buffer(如 Float32List),使用Dart 语言往里填数据,C++ 引擎则会直接读取这段物理内存进行模型的矩阵运算,避免了跨语言传值所带来的性能损耗。 flutter_litert 插件运行的整体架构与数据流程 下图是在Android Flutter项目中使用flutter_litert 插件运行AI模型的整体架构与数据流程图: !litert_architecture_high_res.jpg 从以上的整体流程图中,模型的前向推理过程中的数据流动可以大体分为四个层次和阶段。 1.采集与调度层:Flutter Dart Zone (User Space) 这部分运行在 Flutter 的 Dart 虚拟机中,相当于系统的用户态应用程序。它的首要任务是协调前端 UI 显示与模型检测结果的时序、图像预处理这两部分工作。 当然在模型能够对图像进行检测和识别之前,首先要把模型加载到内存中,模型及其label文件一般整合在app的assets中,因此采用assets对应的API加载模型: 对于手机的摄像头而言,在打开的情况下,其以 30/60fps 的帧率向主线程推送高分辨率的 YUV420 裸流数据并显示在屏幕上。而一般情况下,手机所具备的算力无法支持以这么高的算力实现对每一帧图像的检测,可能1秒钟只能完成10帧图像的处理,这样的情况下,Camera采集图像与Model处理图像这两部分的工作就不是同步的。因此需要分开两个线程同时进行处理,主线程按照Camera的采集帧率刷新显示实时图像,而针对模型对图像的处理而言,就必须开辟一个独立的 Isolate(类似后台高优先级线程),执行 YUV 转 RGB、图像缩放等预处理后送入litert_flutter插件进行识别和检测 。 众所周知,图像在送入YOLO等模型中进行前向推理之前,还必须要进行一系列的预处理流程,以符合模型对输入图像数据在各个维度上的要求。因此,对于每一帧从摄像头中取出的YUV420数据,其分辨率可能是1280x720,那么要进行的预处理过程就至少要包括:分辨率缩放到640x640、YUV转RGB、图像归一化到0-1.0之间、图像数据排列格式调整为NCHW(Pytorch模型的数据排列格式默认为NHWC)等。 以上经过预处理以后,输入图像就准备好了,下一步就是调用flutter_litert插件的API接口进行处理了: 2.跨语言函数接口与内存零拷贝机制 在 Interpreter 对输入图像数据所进行的前向推理的执行流程中,图像数据要从APP应用层的Dart语言传递到模型推理代码的C++语言,而且为了在两种语言之间高效的传递大片的图像内存数据,最好能够直接通过类似内存指针的方式来实现零拷贝的图像内存传递机制,这就是 Flutter 框架为了提升应用程序性能的 Dart FFI (Foreign Function Interface)的用武之地了,它可以允许 Dart 直接与底层 C/C++ 共享同一块物理内存的指针,从而避免在调用者和被调用者之间反复拷贝大片的内存。 如上图所示,无论是在 Dart 语言所写的 interpreter 的函数调用,还是最终 interpreter 把模型的运行结果从底层的C++语言返回给用户态的Dart语言层,都采用了 Dart FFI所提供的内存零拷贝机制。 3.底层算力的执行:Native C++ Zone 这部分是模型使用C/C++语言真正执行前向推理的部分。 在如何理解TFLite/LiteRT的核心概念和框架流程? 一文中,已经详细总结了在Android的TFLite/LiteRT框架下运行AI模型的关键概念和执行流程,Google 使用 C++ 语言写了一个 LiteRT Runtime运行时环境(实际上也就是所谓的interpreter),负责执行和调用 TFLite\LiteRT 格式模型在Android系统中的运行和算子的调度。 具体的算子调度执行过程中,Interpreter 进一步 通过Delegates 来决定把具体的运算算子派发给谁: - GpuDelegate (Adreno GPU): 适合处理模型中大规模并行的浮点矩阵乘法。 - NnApiDelegate (Hexagon NPU): 针对 Android Neural Networks API 设计的专用 NPU。如果模型完全量化为 INT8,交给 NPU 跑不仅极快,而且功耗极低。 - XNNPACK (CPU SIMD): 最底层的兜底方案。如果某个算子 GPU/NPU 不支持,就会退回到 CPU 用向量指令硬算,当然这通常是模型运算速度慢导致卡顿的罪魁祸首。 具体的执行和调度逻辑可以参考如何理解TFLite/LiteRT的核心概念和框架流程?以及TFLite如何处理算子版本和兼容性的问题?这两篇文章。 4.模型返回与渲染 通过以上 LiteRT Runtime 所调度的模型前向推理的执行后,该部分的 C++ 引擎更新内存状态,通过Dart FFI机制,应用层的 Dart 语言层捕获到模型执行完成的信号。此时用户层应用程序就可以按照模型输出的数据结构和类型,从连续的内存块中拆解出 YOLO/RT-DETRv2等模型输出的张量信息(例如类别、边框、置信度等),对这些张量信息进行后处理(如YOLO还需要进行一步NMS处理),然后交回给 Flutter 的 GPU 渲染管道,根据屏幕比例映射坐标,在画布上轻量级地画出最终的目标检测框。 模型推理的GPU/NPU加速设置 如上所述,在LiteRT Runtime运行时环境对模型所进行的前向推理的计算过程中,interpreter 会根据具体算子的版本情况选择对应的delegate执行选项,主要是GPU、NPU和CPU SIMD等选项。那么在flutter框架下使用litert_flutter插件运行AI模型的时候,如何设置使用GPU/NPU来实现这些算子的硬件加速呢? 需要通过 InterpreterOptions 来进行设置,具体代码如下: 以上代码的配置逻辑是,在Interpreter进行算子调度的过程中,优先使用GpuDelegateV2,如果算子在GPU上不支持的话,则会回退到CPU上用4线程来进行计算。 在当前(2026年4月)最新的2.0.11版本的 flutter_litert 插件中,InterpreterOptions 能够支持的加速模式包括: - GPU Delegates (图形处理器):适用于大多数模型,特别是 CNN 类网络。优点是速度快,功耗相对较低。缺点是部分算子不支持,可能回退到 CPU。 - GpuDelegateV2():针对android平台,其底层API是OpenGL ES 3.1 / Vulkan。 - GpuDelegate():针对iOS平台,其底层API是iOS的Metal。 - Core ML Delegate (iOS):针对iOS设备,iOS 11+,A12 芯片以上的设备。优点是在Apple 设备上性能最佳;缺点是仅支持 iOS。 - iOS 上应优先尝试 CoreMLDelegate() ,如果不支持再回退到 GpuDelegate() 。 - XNNPACK Delegate (CPU 优化):无 GPU 或 GPU 不支持时。优点是兼容性比较好,速度快于普通的CPU;缺点是仍比 GPU 慢很多。 需要注意的是:通过options.addDelegate只能设置一个加速选项,如果多次调用addDelegate接口,只有最后一个会生效。因此实践中应使用try…catch的方式选择最合适的加速选项:
- 23 Mar, 2026
Android Studio+Flutter全栈开发环境的搭建及其注意事项
本文完整的记录了在Windows环境中基于Android Studio+Flutter的全栈开发环境的搭建过程,整个过程其实并不复杂,但因为概念众多,再加上中国国内网络访问Google服务器不方便等问题,在首次搭建并测试环境中存在不少值得注意和记录的问题,在此做完整的记录,方便后续开发过程中参考。 Flutter SDK的下载和环境变量设置 从中国国内的镜像源下载Flutter SDK,参考Flutter SDK 归档列表,选择Windows系统的Stable Channel选择下载即可,下载速度要比官方默认源下载快很多: !d99ea2d7-2389-4625-b608-a1796c881a53.png 下载后无需安装,只需要把 Flutter SDK 压缩包解压缩到一个固定的路径中,并把该SDK包中Bin目录的路径设置到Path环境变量中即可。 此外针对国内的网络环境,还需要通过增加环境变量的方式修改 Flutter 社区的地址,在环境变量的用户环境变量中增加两个环境变量:PUB_HOSTED_URL 和 FLUTTER_STORAGE_BASE_URL。 !7024f394-d4b1-4a8b-8e8e-9fee7ad6de79.png 此时,在Windows终端中应该可以通过flutter --version查看当前flutter sdk版本: Android SDK的安装和配置 从Android Studio中文官网下载最新版本的Android Studio并安装:下载 Android Studio 和应用工具 - Android 开发者 | Android Developers。 Android Studio安装完成以后,首次打开还需要在线安装 SDK和NDK等工具,这些工具包也动辄数GB的大小,因此在首次运行Android Studio安装SDK的过程中选择Cutom方式,首先设置HTTP Proxy后再继续后面的SDK安装环节,否则SDK的下载环节会很让人崩溃,可设置的常用Proxy列表如下: !b5eda9af-5302-4c0f-bcb3-c7c5fa3727d0.png 默认情况下 Android Studio 在安装SDK的过程中不会安装命令行工具(Android SDK Command-line Tools),但 Flutter 必须通过它来操作镜像,所以还需要额外安装命令行工具。此外,因为后续我计划要基于Flutter来开发需要调用C/C++语言的音视频和AI模型方面的包和库,还需要安装Android NDK包。 因此,在SDK安装完成后还需要进入 Settings 页面额外安装以下SDK包: !766a7d54-6774-4cef-a456-16a5faf546bf.png 此外,还要在Android Studio中安装下一步使用Flutter进行开发的两个插件:Flutter和Dart。 !4d4dfa01-4df5-4623-b865-6f1a1174c997.png 至此,Flutter SDK、Android Studio及其相关的SDK、Flutter 插件等均安装完毕。 环境测试与验证 下一步在基于Android Studio中使用 Flutter 进行开发之前,可以在终端中使用 flutter doctor 命令检查当前环境的正确性。而在此之前首先通过 flutter doctor --android-licenses 命令并通过按下多次 y 按键来确认一些 Android 的license。最终的 flutter doctor命令的输入大致类似于:因为我不关注web开发,所以不关注此处的Chrome浏览器的报错信息,如果需要web开发的话,额外安装一下Chrome浏览器就可以了。 Gradle 换源 到此还没有结束,在Android Studio中编译和打包Android APK的时候还需要用Gradle,这同样牵扯到一大堆工具的下载。 在 Android APP的构建过程中,Android 的构建脚本 gradle 默认会去从 Google 和 MavenCentral 下载各种依赖包,中国国内网络很容易在这个包下载的过程中卡住,所以需要更改依赖包下载服务器的源地址。 在网上大概搜了一下,大部分都提到通过手动修改 gradle/wrapper/gradle-wrapper.properties 文件修改默认的gradle.org镜像,以及在 android/build.gradle文件中修改其中的 allprojects 等解决方案。这种方式很直观简单,但问题是:以后每次新建一个项目,都需要自行手动去修改这两个文件才行,如果忘记的话就会到外网去下载依赖文件,耗时会非常长。 而我希望做到的是直接把这些修改放到整个环境中,这样每次新建的flutter项目在 build android app的时候自动把下载的服务器地址链接到国内的镜像,而不是访问外网的中心服务器。具体的方式就是在 Gradle 的安装目录(例如我的gradle的安装路径是D:\Android\.gradle,默认的安装路径应该是C盘用户目录下的.gradle目录)下创建一个init.d目录,在其中放一个mirror.init.gradle.kts文件,内容为: 这样在 Gradle 每次加载的时候,都会自动替换与其相关的下载服务器的URL,替换为国内的镜像服务器地址,这样下载速度会快很多。 调试 至此,以上的完整过程就总算是完成了。其实整个过程并不复杂,关键是国内网络访问外网不方便,从外网服务器上的下载速度会非常让人抓狂,而Android Studio/SDK/NDK/Flutter/Gradle等多个环节又需要下载很多包才能完成环境的搭建。好在有国内众多的镜像服务器可以中转,让这个过程和环境一旦完成搭建之后,后续的开发就比较顺畅了。 接下来就是经典的调试过程了,直接在终端中使用Gemini Cli这类终端开发工具或者使用Trae这类 AI IDE 进行代码的修改,然后通过flutter devices + flutter run + r这样的黄金组合进行代码的调试和运行了。正常开发的过程中不需要再打开Android Studio了,只需要使用Android Studio管理和更新自己的SDK就好了。 参考资料 - 在中国网络环境下使用 Flutter - Android Studio快速配置国内镜像源和HTTP代理_android studio 国内代理-CSDN博客