Flutter开发:扫码枪应用

背景

在物流领域中,"把枪" 通常指手持终端设备(Handheld Terminal) ,也被称为 "物流扫码枪""数据采集器" 等。最近做的物流项目,把枪上的应用也是必要环节。

"把枪" 对物流行业的价值

  • 提升效率:替代人工录入,单票货物信息处理时间从分钟级缩短至秒级,分拣效率提升 50% 以上。
  • 降低误差:条码扫描准确率接近 100%,减少人工记录导致的错单、漏单问题。
  • 数据可视化:实时数据同步帮助企业监控物流全流程,优化库存管理、运输路线等。
  • 成本控制:减少人力投入(如仓储盘点人员可减少 30%-50%),长期降低运营成本。

Flutter业务项目

把枪终端 现在基本外观已经类手机化,能承载更为复杂的功能。Flutter上开发基本和普通APP开发一致,只是业务重点全部在 "扫码" 业务。如下图,支持了扫码上车、卸车、揽货、共享。

终端按钮触发扫码动作,扫码运单号后直接发接口对接业务,为了避免扫码遗漏,需要增加清晰的反馈音和记录。

记录

扫码记录直接存在终端存储里,使用SharedPreferences管理存储。当然也可以持久化在数据中进行管理,目前业务上把枪操作员的把枪隶属个人,数据不做采集监控。

js 复制代码
    // 初始化
  void _initErrorScanResult() async {
    SharedPreferences _prefs = await SharedPreferences.getInstance();
    String loadErrorStr = _prefs.get('loadResult') != null ? _prefs.get('loadResult').toString() : '[]';
    var loadErrors = json.decode(loadErrorStr);
    List<ScanResData> _allRecords = (loadErrors as List<dynamic>).map((e) => ScanResData.fromJson(e)).toList();
    setState(() {
      _successRecords = _allRecords.where((v) => v.status == 'success').toList();
      _errRecords = _allRecords.where((v) => v.status == 'error').toList();
    });
  }
  
  
    // 移除
  void _remove(String target, String status, int index) async {
    setState(() {
      if (status == 'error') {
        _errRecords = _errRecords.asMap().entries.where((indexValue) => indexValue.key != index).map((v) => v.value).toList();
      } else {
        _successRecords = _successRecords.asMap().entries.where((indexValue) => indexValue.key != index).map((v) => v.value).toList();
      }

      _reset();
    });
  }
   // 重置
  Future<void> _reset() async {
    SharedPreferences _prefs = await SharedPreferences.getInstance();
    List<ScanResData> _mergeRecords = [];
    _mergeRecords.addAll(_errRecords);
    _mergeRecords.addAll(_successRecords);
    _prefs.setString('unloadResult', json.encode(_mergeRecords));
  }

扫码防干扰

如下图物流包裹上贴的快递单,在扫码时上面的一维码以及下面的二维码都会触发把枪扫描成功,因为扫码距离的原因,有一定概率扫上二维码,影响操作效率。在事件回调中排除掉二维码链接。

js 复制代码
  @override
  void onEvent(Object event) {
    G.print.info(event.toString(), '扫码结果');
    String? code = event as String;
    if (Utils.isLink(code)) return;
    if (code.isNotEmpty && !_saving) {
      setState(() {
        formData.waybillNo = code;
        formData.waybillNoList = [code];
        _save();
      });
    } else {}
  }

扫码插件

扫码插件使用的是pda_scanner 0.2.9,This is a scanning plug-in for PDA to listen the scanned events and get scanning results.

pda_scanner 插件是用于 Flutter 应用与 PDA(掌上电脑)扫码设备对接的中间件。它通过特定的通信机制实现应用与硬件设备的交互。因为flutter升级缘故,拉到本地进行管理。

js 复制代码
  pda_scanner:
    path: ../packages/logistic-pda-plugin

使用也很简单

1. with PdaListenerMixin<PdaScanLoad> 的作用

Mixin 混入机制

  • 概念:Mixin 是 Dart 中的一种代码复用方式,允许类在不继承的情况下使用其他类的方法和属性。

  • 语法 :通过 with 关键字将 Mixin 添加到类中。

  • 示例代码分析

    dart

    scala 复制代码
    class _PdaScanLoadState extends State<PdaScanLoad> with PdaListenerMixin<PdaScanLoad> {
      // ...
    }
    • _PdaScanLoadState 类继承自 State<PdaScanLoad>,同时混入了 PdaListenerMixin
    • PdaListenerMixin<PdaScanLoad> 是一个泛型 Mixin,它提供了监听 PDA 扫描设备的功能(如扫码回调、错误处理)。
    • 优势 :无需继承复杂的类层次结构,直接复用 PdaListenerMixin 的功能。

2. @override 注解的作用

方法重写(Override)

  • 概念:子类重新实现父类或 Mixin 中已有的方法。

  • 语法 :使用 @override 注解标记重写的方法(非强制,但推荐)。

  • 示例代码分析

    dart

    less 复制代码
    @override
    void onEvent(Object event) {
      // 处理扫码事件
    }
    
    @override
    void onError(Object error) {
      // 处理扫码异常
    }
    • onEventonErrorPdaListenerMixin 中定义的抽象或具体方法。
    • @override 明确告诉编译器:这个方法是重写父类或 Mixin 的方法,避免拼写错误。

3. 结合场景:PDA 扫码功能

  • Mixin 的功能PdaListenerMixin 提供了监听 PDA 设备的能力,可能包含:

    • 初始化 PDA 设备连接
    • 接收扫码事件的回调机制
    • 错误处理逻辑
  • 重写的目的

    • onEvent:处理扫码结果(如保存运单号)。
    • onError:处理扫码异常(如播放提示音)。
js 复制代码
import 'package:pda_scanner/pda_listener_mixin.dart';

class _PdaScanLoadState extends State<PdaScanLoad> with PdaListenerMixin<PdaScanLoad> {

  @override
  void onEvent(Object event) {
    G.print.info(event.toString(), '扫码结果');
    String? code = event as String;
    if (Utils.isLink(code)) return;
    if (code.isNotEmpty && !_saving) {
      setState(() {
        formData.waybillNo = code;
        formData.waybillNoList = [code];
        _save();
      });
    } else {}
  }

  @override
  void onError(Object error) {
    G.print.info(error.toString(), '扫码异常日志');
    Utils.speakToast('扫码异常');
  }
  
}

后记

刚开始接触时,因为是新型终端的缘故,心理上还是比较有压力。实际接触扫码枪实物并使用后,发现在场景相对单一的终端上难度很小。因为扫码机型号的统一装配使用,也没有各类型手机应用带来的诸多兼容性问题。扫码机相对比较有质感,看起来很皮实,虽然基本功能类手机,不过应用做的越简单越好。

相关推荐
LawrenceLan14 小时前
Flutter 零基础入门(九):构造函数、命名构造函数与 this 关键字
开发语言·flutter·dart
一豆羹15 小时前
macOS 环境下 ADB 无线调试连接失败、Protocol Fault 及端口占用的深度排查
flutter
行者9615 小时前
OpenHarmony上Flutter粒子效果组件的深度适配与实践
flutter·交互·harmonyos·鸿蒙
行者9618 小时前
Flutter与OpenHarmony深度集成:数据导出组件的实战优化与性能提升
flutter·harmonyos·鸿蒙
小雨下雨的雨18 小时前
Flutter 框架跨平台鸿蒙开发 —— Row & Column 布局之轴线控制艺术
flutter·华为·交互·harmonyos·鸿蒙系统
小雨下雨的雨18 小时前
Flutter 框架跨平台鸿蒙开发 —— Center 控件之完美居中之道
flutter·ui·华为·harmonyos·鸿蒙
小雨下雨的雨19 小时前
Flutter 框架跨平台鸿蒙开发 —— Icon 控件之图标交互美学
flutter·华为·交互·harmonyos·鸿蒙系统
小雨下雨的雨19 小时前
Flutter 框架跨平台鸿蒙开发 —— Placeholder 控件之布局雏形美学
flutter·ui·华为·harmonyos·鸿蒙系统
行者9620 小时前
OpenHarmony Flutter弹出菜单组件深度实践:从基础到高级的完整指南
flutter·harmonyos·鸿蒙
前端不太难20 小时前
Flutter / RN / iOS,在长期维护下的性能差异本质
flutter·ios