美文网首页
flutter:小票标签打印【跨平台解决方案】

flutter:小票标签打印【跨平台解决方案】

作者: 李小轰 | 来源:发表于2023-03-14 17:57 被阅读0次

引言

使用 flutter 进行 pos 软件开发,诸多的业务场景都涉及到了 小票标签 打印。基于通用化,跨平台的设计要求,小编整理了这篇文章。

核心设计思想

跨平台通用化方案我们主要解决以下三点:


  • 票据样式: 拒绝硬编码,直接使用 flutter-widget 进行样式开发,更加直观灵活

  • 打印指令集: 不嵌入厂商的打印SDK,适配一码多用,无后续接入开发消耗

  • 传输方式: 指令集传输方式可扩展,底层代码无需变动

整体方案流程

票据样式使用 flutter-widget 进行开发,打印策略使用光栅位图的统一标准进行指令集中转,所有的数据转换在 dart 层完成,网络打印机使用 dart-socket 进行传输,usb 传输封装各平台的 write 方法。

整个工具库做统一数据中转,各平台无需考虑数据层的处理,只处理数据传输。

步骤一: 将 widget 转换打印图层

使用 flutter-widget 开发票据样式,数据填充 widget 后,加入队列转 Uint8List 图像数据

功能实现可直接使用我们的开源库 print_image_generate_tool,提供能力将 widget 视图转换成 Uint8List 数据,内部维护队列,按加入顺序生成返回图像数据。

使用方式:

  1. 初始化打印图层
    在页面根节点下将打印图层 PrintImageGenerateWidget 初始化
MaterialApp(
    onGenerateTitle: (context) => '打印测试',
    home: Scaffold(
    body: PrintImageGenerateWidget(
       contentBuilder: (context) {
       return const HomePage();
       },
       onPictureGenerated: _onPictureGenerated,  //第三点说明
     ),
   ),
)
  1. 将 widget 生成图层数据,注意: 传入的 tempWidget 必须实现或继承父类 ATempWidget
///生成打印的模板 Widget 需要继承这个类
mixin ATempWidget {
  //生成图片的缩放倍数
  double get pixelRatio => 1;

  //需要生成的票据像素宽度
  int get pixelPagerWidth;

  //需要生成的票据像素高度
  int get pixelPagerHeight => -1;
}
// 生成打印图层任务,指定任务类型为标签
    PictureGeneratorProvider.instance.addPicGeneratorTask(
      PicGenerateTask<PrinterInfo>(
        tempWidget: child() as ATempWidget,
        printTypeEnum: PrintTypeEnum.label,
        params: printerInfo,
      ),
    );
// 生成打印图层任务,指定任务类型为小票
    PictureGeneratorProvider.instance.addPicGeneratorTask(
      PicGenerateTask<PrinterInfo>(
        tempWidget: child() as ATempWidget,
        printTypeEnum: PrintTypeEnum.receipt,
        params: printerInfo,
      ),
    );
  1. 接收打印图像结果,如上 PrintImageGenerateWidget 中需要注入 onPictureGenerated 方法,接收打印图像结果 Uint8List
//打印图层生成成功
  Future<void> _onPictureGenerated(PicGenerateResult data) async {
    //widget生成的图像的字节结果
    final imageBytes = data.data;
    //打印票据类型(标签、小票)
    final printTypeEnum = printTask.printTypeEnum;
    ... 省略打印逻辑
  }

步骤二:打印图层转打印指令集

将 widget 转换打印图层后,我们需要将 Uint8List 数据转换为打印机可识别的数据类型,ESC 对应小票机,TSC 对应标签机。

使用 flutter_printer_plus 开源库进行功能实现:

// 转 TSC 字节,imageBytes 类型为 Uint8List
var printData = await PrinterCommandTool.generatePrintCmd(
        imgData: imageBytes,
        printType: PrintTypeEnum.label,
      );
// 转 ESC 字节,imageBytes 类型为 Uint8List
var printData = await PrinterCommandTool.generatePrintCmd(
        imgData: imageBytes,
        printType: PrintTypeEnum.receipt,
      );

步骤三:目标设备发送数据

可以自行扩展实现 write 方法,也可以使用 flutter_printer_plus 内提供的方式。目前已提供的实现如下:

  • USB 传输 (USB打印机)

flutter_printer_plus 提供获取当前已连接的打印机列表,列表内每一个元素类型为 usbDevice。

// usb 打印
        final conn = UsbConn(usbDevice);
        conn.writeMultiBytes(printData, 1024 * 3);
  • IP 传输(网口打印机)

example 内提供获取局域网内可用打印机样例

// IP 打印
        final conn = NetConn(ip);
        conn.writeMultiBytes(printData);

完整流程级具体实现逻辑可参考 example 示例

建议使用者将上层进行封装(维护队列),打印图层生成成功后先将图像保存本地,等待上一个打印任务结束后再从队列中获取本地图片进行下一个打印任务,避免造成内存抖动。

附上 demo 打印的小票样式

小票样式

疑难点记录

1. 打印的票据,一半正常,一半显示乱码

原因:数据太大导致打印机内存溢出输出乱码。
处理:对图片进行分割处理,分成n个小段进行打印 长图切割实现方式参考

2. 打印机打印票据,出票缓慢,声音卡顿

原因:打印的位图宽度太大。
处理:将位图宽度进行缩小,问题解决。以 80mm 宽度小票为例,通常 1mm 等于 8个像素,因为宽度适配在实际打印中有偏差,不宜设置为完全吻合因此,适合小票打印机打印的图片像素尺寸应为:558px、372px。

开源工具库

print_image_generate_tool:提供 widget 转图像数据(Uint8List)能力;

flutter_printer_plus:提供图像数据(Uint8List) 转 TSC 、ESC能力,提供 ip、usb 打印支持;

esc_utils:小票打印机数据转换工具,提供图像数据(Uint8List) 转 ESC 能力;

tsc_utils:标签打印机数据转换工具,提供图像数据(Uint8List) 转 TSC 能力;

android_usb_printer:flutter android 端插件,提供 usb 打印机 搜索、写入 等能力;

相关文章

网友评论

      本文标题:flutter:小票标签打印【跨平台解决方案】

      本文链接:https://www.haomeiwen.com/subject/hvdkrdtx.html