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('扫码异常');
  }
  
}

后记

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

相关推荐
sunly_11 小时前
Flutter:视频预览功能
javascript·flutter·音视频
勤劳打代码14 小时前
条分缕析 —— 通过 Demo 深入浅出 Provider 原理
flutter·面试·dart
2501_9159184115 小时前
Flutter 加固方案对比与实战,多工具组合的跨平台安全体系(Flutter App 加固/IPA 成品混淆/Ipa Guard CLI/自动化安全流程)
安全·flutter·ios·小程序·uni-app·自动化·iphone
Bryce李小白15 小时前
Flutter中mixing的原理及应用场景
flutter
_大学牲15 小时前
从 0 到上架:用 Flutter 一天做一款功德木鱼
前端·flutter·apple
嚴寒15 小时前
2025最终!Mac配置Flutter全平台开发环境完整指南(亲测有效)
前端·flutter
Bryce李小白1 天前
Flutter版本管理工具FVM
flutter
程序员老刘1 天前
Dart 3.7格式化工具“乱改代码”?强迫症必看
flutter·代码规范·dart
猫林老师1 天前
Flutter for HarmonyOS开发指南(二):混合开发架构与通信机制
flutter·架构·harmonyos