Flutter USB ESC指令打印机控制插件usb_esc_printer_windows的使用

发布于 1周前 作者 yibo5220 来自 Flutter

Flutter USB ESC指令打印机控制插件usb_esc_printer_windows的使用

简介

usb_esc_printer_windows 是一个用于在Windows平台上通过ESC/POS指令控制USB打印机的Flutter插件。该插件使用Dart FFI(Foreign Function Interface)来调用本地代码。

使用步骤

项目结构

该项目的结构如下:

  • src: 包含本地源代码以及Cmake文件,用于构建动态库。
  • lib: 包含定义插件API的Dart代码,并调用本地代码。
  • 平台文件夹 (android, ios, windows 等): 包含构建和捆绑本地代码库所需的构建文件。

构建和捆绑本地代码

pubspec.yaml 文件配置如下:

plugin:
  platforms:
    some_platform:
      ffiPlugin: true

这会为各个目标平台调用本地构建系统并捆绑二进制文件到Flutter应用中。

绑定到本地代码

为了使用本地代码,需要在Dart中生成绑定。这些绑定由package:ffigensrc/usb_esc_printer_windows.h头文件生成。可以通过运行以下命令重新生成绑定:

flutter pub run ffigen --config ffigen.yaml

调用本地代码

对于短时间运行的本地函数,可以直接从任何隔离中调用。例如,查看lib/usb_esc_printer_windows.dart中的sum函数。

对于长时间运行的函数,应该在一个辅助隔离中调用以避免在Flutter应用中丢帧。例如,查看lib/usb_esc_printer_windows.dart中的sumAsync函数。

完整示例代码

以下是完整的示例代码,展示了如何使用usb_esc_printer_windows插件进行打印操作:

import 'package:esc_pos_utils_plus/esc_pos_utils_plus.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:image/image.dart' as img;
import 'package:usb_esc_printer_windows/usb_esc_printer_windows.dart' as usb_esc_printer_windows;

void main() {
  runApp(const MyApp());
}

class MyApp extends StatefulWidget {
  const MyApp({super.key});

  [@override](/user/override)
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  final String _printerName = "EPSON";
  late Future<CapabilityProfile> _profile;

  [@override](/user/override)
  initState() {
    _profile = CapabilityProfile.load();
    super.initState();
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Fluter ESC/POS Printer Pakage For Windows Platform Only'),
        ),
        body: SingleChildScrollView(
          child: Container(
            padding: const EdgeInsets.all(10),
            child: Column(
              children: [
                ElevatedButton(
                  onPressed: printReq,
                  child: const Text("Demo Print"),
                )
              ],
            ),
          ),
        ),
      ),
    );
  }

  Future<Uint8List> loadImageFromAssets(String path) async {
    final ByteData data = await rootBundle.load(path);
    return data.buffer.asUint8List();
  }

  printReq() async {
    List<int> bytes = [];
    final profile = await _profile;
    final generator = Generator(PaperSize.mm80, profile);

    // LOGO
    final Uint8List data = await loadImageFromAssets('assets/images/logo.png');

    img.Image originalImage = img.decodeImage(data)!;

    bytes += generator.imageRaster(originalImage, align: PosAlign.center);
    bytes += generator.feed(1);

    // GENERATE BARCODE
    String invoiceNo = "322123000000";
    List<int> barData = invoiceNo.split('').map((String digit) => int.parse(digit)).toList();

    bytes += generator.barcode(
      Barcode.itf(barData),
      height: 100,
      textPos: BarcodeText.none,
    );

    bytes += generator.feed(1);

    bytes += generator.text(
      'INV #322123000000',
      styles: const PosStyles(
        align: PosAlign.center,
        height: PosTextSize.size2,
        width: PosTextSize.size2,
      ),
    );

    bytes += generator.text('Reprinted at : 06-11-2023 07:32:52 AM');

    bytes += generator.feed(1);

    bytes += generator.text(
      'PAID(IN)',
      styles: const PosStyles(
        align: PosAlign.center,
        height: PosTextSize.size2,
        width: PosTextSize.size2,
      ),
    );

    bytes += generator.feed(1);

    bytes += generator.text('Walk in');

    bytes += generator.text('Tel : 0000000000');

    bytes += generator.text('Date\\Time : Sun, 10 Sep 2023 06:24 PM');

    bytes += generator.text('Associate : 5552');

    bytes += generator.text('Promised On : Sun, 10 Sep 2023 06:24 PM');

    bytes += generator.feed(1);

    bytes += [27, 97, 0];
    bytes += generator.row([
      PosColumn(
        text: 'QTY',
        width: 1,
        styles: const PosStyles(
          align: PosAlign.left,
          bold: true,
        ),
      ),
      PosColumn(
        text: 'S/T/DESCRIPTION',
        width: 8,
        styles: const PosStyles(
          align: PosAlign.left,
          bold: true,
        ),
      ),
      PosColumn(
        text: 'TOTAL',
        width: 3,
        styles: const PosStyles(
          align: PosAlign.left,
          bold: true,
        ),
      ),
    ]);

    bytes += [27, 97, 1];
    bytes += generator.text('-----------------------------------------');

    bytes += [27, 97, 0];
    bytes += generator.text(
      ' 1x  Pants (IN)                  \$ 133.40',
      styles: const PosStyles(
        align: PosAlign.left,
        reverse: true,
        bold: true,
      ),
    );

    bytes += generator.feed(1);

    bytes += [27, 97, 1];

    // GENERATE BARCODE
    bytes += generator.barcode(
      Barcode.itf(
        "32212300000000".split('').map((String digit) => int.parse(digit)).toList(),
      ),
      height: 50,
      textPos: BarcodeText.none,
    );

    bytes += generator.text("32212300000000");

    bytes += generator.feed(1);

    bytes += [27, 97, 0];
    bytes += generator.row([
      PosColumn(
        text: '1x',
        width: 1,
        styles: const PosStyles(
          align: PosAlign.left,
        ),
      ),
      PosColumn(
        text: '(\$13.40 Growth Hem)',
        width: 11,
        styles: const PosStyles(
          align: PosAlign.left,
        ),
      ),
    ]);

    bytes += [27, 97, 0];
    bytes += generator.row([
      PosColumn(
        text: '',
        width: 1,
        styles: const PosStyles(
          align: PosAlign.left,
        ),
      ),
      PosColumn(
        text: '(Tag : (1x) Lengthen : Lengthen \$ 0.00',
        width: 11,
        styles: const PosStyles(
          align: PosAlign.left,
        ),
      ),
    ]);

    bytes += [27, 97, 0];
    bytes += generator.row([
      PosColumn(
        text: '',
        width: 1,
        styles: const PosStyles(
          align: PosAlign.left,
        ),
      ),
      PosColumn(
        text: '| (1x) Lengthen : Polo Hem \$ 0.00) |',
        width: 11,
        styles: const PosStyles(
          align: PosAlign.left,
        ),
      ),
    ]);

    bytes += [27, 97, 0];
    bytes += generator.row([
      PosColumn(
        text: '',
        width: 1,
        styles: const PosStyles(
          align: PosAlign.left,
        ),
      ),
      PosColumn(
        text: 'Dept Hem',
        width: 11,
        styles: const PosStyles(
          align: PosAlign.left,
          bold: true,
        ),
      ),
    ]);

    bytes += generator.feed(1);

    bytes += [27, 97, 0];
    bytes += generator.text(
      ' 1x  Pants (IN)                  \$ 133.40',
      styles: const PosStyles(
        align: PosAlign.left,
        reverse: true,
        bold: true,
      ),
    );

    bytes += generator.feed(1);

    bytes += [27, 97, 1];

    // GENERATE BARCODE
    bytes += generator.barcode(
      Barcode.itf(
        "32212300000000".split('').map((String digit) => int.parse(digit)).toList(),
      ),
      height: 50,
      textPos: BarcodeText.none,
    );

    bytes += generator.text("32212300000000");

    bytes += generator.feed(1);

    bytes += [27, 97, 0];
    bytes += generator.row([
      PosColumn(
        text: '1x',
        width: 1,
        styles: const PosStyles(
          align: PosAlign.left,
        ),
      ),
      PosColumn(
        text: '(\$13.40 Growth Hem)',
        width: 11,
        styles: const PosStyles(
          align: PosAlign.left,
        ),
      ),
    ]);

    bytes += [27, 97, 0];
    bytes += generator.row([
      PosColumn(
        text: '',
        width: 1,
        styles: const PosStyles(
          align: PosAlign.left,
        ),
      ),
      PosColumn(
        text: '(Tag : (1x) Lengthen : Lengthen \$ 0.00',
        width: 11,
        styles: const PosStyles(
          align: PosAlign.left,
        ),
      ),
    ]);

    bytes += [27, 97, 0];
    bytes += generator.row([
      PosColumn(
        text: '',
        width: 1,
        styles: const PosStyles(
          align: PosAlign.left,
        ),
      ),
      PosColumn(
        text: '| (1x) Lengthen : Polo Hem \$ 0.00) |',
        width: 11,
        styles: const PosStyles(
          align: PosAlign.left,
        ),
      ),
    ]);

    bytes += [27, 97, 0];
    bytes += generator.row([
      PosColumn(
        text: '',
        width: 1,
        styles: const PosStyles(
          align: PosAlign.left,
        ),
      ),
      PosColumn(
        text: 'Dept Hem',
        width: 11,
        styles: const PosStyles(
          align: PosAlign.left,
          bold: true,
        ),
      ),
    ]);

    bytes += generator.feed(1);

    bytes += [27, 97, 1];
    bytes += generator.text('-----------------------------------------');

    bytes += [27, 97, 0];
    bytes += generator.text(
      'HST # : R877439000',
      styles: const PosStyles(
        height: PosTextSize.size1,
      ),
    );

    bytes += [27, 97, 2];
    bytes += generator.text('Sub Total  \$ 13.40');

    bytes += [27, 97, 0];
    bytes += generator.text('Total Disc \$ 0.00');

    bytes += [27, 97, 2];
    bytes += generator.text('HST (13%)  \$ 1.74');

    bytes += generator.feed(1);

    bytes += [27, 97, 2];
    bytes += generator.text(
      'Total  \$ 15.14',
      styles: const PosStyles(
        height: PosTextSize.size2,
        bold: true,
      ),
    );

    bytes += generator.text(
      'Balance Owing  \$ 0.00',
      styles: const PosStyles(
        height: PosTextSize.size2,
        bold: true,
      ),
    );

    bytes += generator.feed(1);

    bytes += [27, 97, 1];
    bytes += generator.text('Transaction details');
    bytes += generator.text('*****************************************');

    bytes += [27, 97, 0];
    bytes += generator.text('Tender Type :  Cash(INV)');
    bytes += generator.text('Amount :  \$ 0.00');

    bytes += [27, 97, 2];
    bytes += generator.text('Total Tendered  \$ 13.40');
    bytes += generator.text('Total Charge  \$ 0.00');
    bytes += generator.text('Total Round Off  \$ 0.01');

    bytes += [27, 97, 0];
    bytes += generator.text('Items :  1');

    bytes += [27, 97, 1];
    bytes += generator.text(
      'Production : Sun, 10 Sep 2023 09:00 AM',
      styles: const PosStyles(
        height: PosTextSize.size2,
        bold: true,
      ),
    );

    bytes += generator.feed(1);

    bytes += [27, 97, 2];
    bytes += generator.text('Points Earned Before This Visit : \$ 739.85');
    bytes += generator.text('Total Points Earned :  \$ 0.57');

    // 0 = left, center = 1 right = 2
    bytes += [27, 97, 1];
    bytes += generator.text('*** Store Copy ***');

    bytes += generator.feed(1);
    bytes += generator.cut();

    final res = await usb_esc_printer_windows.sendPrintRequest(bytes, _printerName);
    String msg = "";

    if (res == "success") {
      msg = "Printed Successfully";
    } else {
      msg = "Failed to generate a print please make sure to use the correct printer name";
    }

    print(msg);
  }
}

更多关于Flutter USB ESC指令打印机控制插件usb_esc_printer_windows的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter USB ESC指令打印机控制插件usb_esc_printer_windows的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是如何在Flutter应用中使用usb_esc_printer_windows插件来控制USB ESC指令打印机的示例代码。这个插件允许你在Windows平台上通过USB接口发送ESC/POS指令来控制打印机。

首先,确保你已经在pubspec.yaml文件中添加了usb_esc_printer_windows依赖:

dependencies:
  flutter:
    sdk: flutter
  usb_esc_printer_windows: ^最新版本号  # 替换为实际最新版本号

然后,运行flutter pub get来安装依赖。

接下来,在Flutter项目中,你可以使用以下代码来初始化插件并发送打印指令。

1. 导入插件

在你的Dart文件中导入插件:

import 'package:usb_esc_printer_windows/usb_esc_printer_windows.dart';

2. 初始化插件并搜索打印机

你需要先初始化插件并搜索连接的USB打印机:

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  UsbEscPrinterWindows printer = UsbEscPrinterWindows();

  // 搜索连接的USB打印机
  List<UsbDevice> devices = await printer.listDevices();
  print('Found devices: $devices');

  // 假设我们选择了第一个设备(实际应用中,你可能需要让用户选择设备)
  if (devices.isNotEmpty) {
    UsbDevice selectedDevice = devices.first;
    await printer.openDevice(selectedDevice);

    // 在这里发送打印指令
    await sendPrintCommand(printer);

    // 关闭设备连接
    await printer.closeDevice();
  } else {
    print('No USB ESC/POS printer found.');
  }

  runApp(MyApp());
}

3. 发送打印指令

定义一个函数来发送ESC/POS指令到打印机:

Future<void> sendPrintCommand(UsbEscPrinterWindows printer) async {
  // 示例ESC/POS指令:初始化打印机,打印文本,并切纸
  List<int> escPosCommands = [
    // 初始化打印机
    0x1B, 0x40, // 初始化指令
    
    // 设置对齐方式为居中
    0x1B, 0x61, 0x01, // 对齐中心
    
    // 打印文本
    0x1B, 0x21, 33, // 设置字体大小为A(宽度33),高度也是33(默认)
    0x48, 0x65, 0x6C, 0x6C, 0x6F, // 'Hello'的ASCII码
    0x0A, // 换行
    
    // 切纸
    0x1B, 0x66, 0x01 // 切纸指令
  ];

  // 发送指令到打印机
  await printer.write(escPosCommands);
}

4. 完整示例

将上述代码整合到一个完整的Flutter应用中:

import 'package:flutter/material.dart';
import 'package:usb_esc_printer_windows/usb_esc_printer_windows.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  UsbEscPrinterWindows printer = UsbEscPrinterWindows();

  List<UsbDevice> devices = await printer.listDevices();
  print('Found devices: $devices');

  if (devices.isNotEmpty) {
    UsbDevice selectedDevice = devices.first;
    await printer.openDevice(selectedDevice);

    runApp(MyApp(printer: printer));
  } else {
    print('No USB ESC/POS printer found.');
    runApp(MyApp(printer: null));
  }
}

class MyApp extends StatelessWidget {
  final UsbEscPrinterWindows? printer;

  MyApp({this.printer});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('USB ESC/POS Printer Control'),
        ),
        body: Center(
          child: printer != null
              ? ElevatedButton(
                  onPressed: () async {
                    await sendPrintCommand(printer!);
                  },
                  child: Text('Print'),
                )
              : Text('No printer found.'),
        ),
      ),
    );
  }
}

Future<void> sendPrintCommand(UsbEscPrinterWindows printer) async {
  List<int> escPosCommands = [
    0x1B, 0x40,
    0x1B, 0x61, 0x01,
    0x1B, 0x21, 33,
    0x48, 0x65, 0x6C, 0x6C, 0x6F,
    0x0A,
    0x1B, 0x66, 0x01
  ];

  await printer.write(escPosCommands);
}

在这个示例中,我们搜索USB设备,选择第一个设备(实际应用中,你可能需要让用户从列表中选择设备),并在点击按钮时发送打印指令。请确保在实际应用中处理错误和异常情况,并根据需要调整ESC/POS指令。

回到顶部