Flutter扩展打印机功能插件sunmi_ext_printer的使用

Flutter扩展打印机功能插件sunmi_ext_printer的使用

支持Sunmi外部打印机,基于Sunmi官方SDK文档。

主要功能

  • 打印文本
  • 打印图像
  • 打印二维码
  • 打印条形码
  • 打印表格
  • 纸张切割
  • 纸张进纸
  • 对齐方式:
    • 左对齐,居中对齐,右对齐
  • 样式:
    • 加粗,X轴和Y轴坐标缩放
  • 发送原始数据
  • 查找蓝牙打印机
    • 对于蓝牙权限,应在Flutter应用内处理,例如使用permission_handler插件

示例

查找已配对的蓝牙设备

Set<String> _bluetoothIds = {};

void findBleDevices() async {
  var res = await pos.findBleDevice();
  Set<String> ids = {};
  if (res != null) {
    for (var i = 0; i < res.length; i++) {
      ids.add('${res[i]}');
    }
  }

  setState(() {
    _bluetoothIds = ids;
  });
}

打印文本

// 请将deviceID更改为扫描结果中的蓝牙地址
var deviceID = '74:F7:F:FD:41:0D';

final pos = SunmiExtPrinter();
await pos.setPrinter(SunmiPrinter.SunmiBlueToothPrinter, deviceID);
await pos.connectPrinter();

await pos.setAlignMode(AlignMode.Center);
await pos.printText("Rubybear\n");

打印二维码

await pos.lineWrap();
await pos.printQrCode("https://edesoft.com/en.html");
await pos.lineWrap();

打印图像

var bytes = await rootBundle.load('images/logo.png');
var buf = bytes.buffer.asUint8List();
await pos.printImage(buf);
await pos.lineWrap();

确保在pubspec.yaml中定义了资产:

assets:
  - images/logo.png

确保images/logo.png文件存在于正确的文件夹中。

[可选] 您可能需要在发送到打印机之前调整图像大小,以防止打印过大。可以使用image包来完成此操作。例如:

import 'package:image/image.dart' as img;

Future<Uint8List> _convertImage(Uint8List imageBytes, int? printWidth, int? printHeight, bool invert) async {
  var cmd = img.Command()
    ..decodeImage(imageBytes)
    ..grayscale();
  await cmd.executeThread();

  if (printWidth == null && printHeight == null) {
    printWidth = 256;
  }

  cmd.copyResize(width: printWidth, height: printHeight);

  if (invert) {
    cmd.invert();
  }
  cmd.encodeBmp();
  await cmd.executeThread();

  var bitmapBytes = cmd.outputBytes ?? imageBytes;
  return bitmapBytes;
}

打印表格

await pos.enableBold(true);
await pos.printColumnsText(["Item", "Qty", "Amt"], [18, 6, 8], [0, 2, 2]);

await pos.enableBold(false);
await pos.printColumnsText(["Carlsberg Bottle", "2", "20.00"], [18, 6, 8], [0, 2, 2]);
await pos.printColumnsText(["Milk 2L", "1", "3.50"], [18, 6, 8], [0, 2, 2]);

页面切割

await pos.cutPaper(PaperCutMode.FullCut);

刷新

await pos.flush();

示例代码

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

import 'package:flutter/material.dart';

import 'package:sunmi_ext_printer/enums.dart';
import 'package:sunmi_ext_printer/sunmi_ext_printer.dart';

import 'package:permission_handler/permission_handler.dart';

import 'package:flutter/services.dart' show PlatformException, rootBundle;

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> {
  Set<String> _bluetoothIds = {};

  [@override](/user/override)
  void initState() {
    super.initState();
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Printer example app'),
        ),
        body: Center(
            child: Column(
          mainAxisAlignment: MainAxisAlignment.start,
          children: [
            const SizedBox(
              height: 20,
            ),
            ElevatedButton.icon(
                onPressed: () => permitBleThenFind(context),
                icon: const Icon(Icons.search),
                label: const Text("搜索蓝牙打印机")),
            for (var id in _bluetoothIds) BluetoothRow(id),
          ],
        )),
      ),
    );
  }

  void permitBleThenFind(BuildContext context) async {
    var ok = await Permission.bluetooth.request().isGranted &&
        await Permission.bluetoothConnect.request().isGranted;
    if (ok) {
      findBleDevices();
    }
  }

  void findBleDevices() async {
    var res = await SunmiExtPrinter().findBleDevice();
    Set<String> ids = {};
    if (res != null) {
      for (var i = 0; i < res.length; i++) {
        ids.add('${res[i]}');
      }
    }

    setState(() {
      _bluetoothIds = ids;
    });
  }
}

class BluetoothRow extends StatefulWidget {
  final String deviceID;
  const BluetoothRow(this.deviceID, {super.key});

  [@override](/user/override)
  State<BluetoothRow> createState() => _BluetoothRowState();
}

class _BluetoothRowState extends State<BluetoothRow> {
  bool _isRunning = false;

  _BluetoothRowState();

  Future<void> _print() async {
    setState(() {
      _isRunning = true;
    });
    try {
      printReceipt(widget.deviceID);
    } on PlatformException catch (ex) {
      _showMyDialog(context, 'Error', ex.message);
    } catch (ex) {
      _showMyDialog(context, 'Unknown Error', ex);
    } finally {
      setState(() {
        _isRunning = false;
      });
    }
  }

  Future<void> printReceipt(deviceID) async {
    final pos = SunmiExtPrinter();
    await pos.setPrinter(SunmiPrinter.SunmiBlueToothPrinter, deviceID);
    await pos.connectPrinter();

    await pos.setAlignMode(AlignMode.Center);
    await pos.setFontZoom(2, 2);
    await pos.enableBold(true);
    await pos.printText("Rubybear\n");
    await pos.lineWrap();

    await pos.setFontZoom(1, 1);
    await pos.enableBold(false);
    await pos.printText("1888 Super Road\nWanda Plaza\nShanghai, China\n");
    await pos.lineWrap();

    var bytes = await rootBundle.load('images/logo.png');
    var buf = bytes.buffer.asUint8List();
    await pos.printImage(buf);
    await pos.lineWrap();

    await pos.enableBold(true);
    await pos.printText("Retail Invoice\n");
    await pos.lineWrap();

    await pos.enableBold(false);
    await pos.setAlignMode(AlignMode.Left);
    await pos.printText("Date: 09/15/2022, 15:35\n");
    await pos.printText("Payment Mode: AliPay\n");
    await pos.printText("--------------------------------\n");

    await pos.enableBold(true);
    await pos.printColumnsText(["Item", "Qty", "Amt"], [18, 6, 8], [0, 2, 2]);

    await pos.enableBold(false);
    await pos.printColumnsText(
        ["Carlsberg Bottle", "2", "20.00"], [18, 6, 8], [0, 2, 2]);
    await pos.printColumnsText(["Milk 2L", "1", "3.50"], [18, 6, 8], [0, 2, 2]);
    await pos
        .printColumnsText(["Ice Cream", "5", "20.00"], [18, 6, 8], [0, 2, 2]);

    await pos.printText("--------------------------------\n");
    await pos.enableBold(true);
    await pos.printColumnsText(["TOTAL", "43.50"], [16, 16], [0, 2]);

    await pos.setAlignMode(AlignMode.Center);
    await pos.enableBold(false);
    await pos.lineWrap();
    await pos
        .printText("This is your official receipt\nThank you come again!\n");
    await pos.printText("Please scan and check more\n");
    await pos.lineWrap();
    await pos.printQrCode("https://edesoft.com/en.html");

    await pos.lineWrap(n: 4);
    await pos.cutPaper(PaperCutMode.FullCut);
    await pos.flush();
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Padding(
        padding: const EdgeInsets.all(10),
        child: Card(
            child: Row(
          mainAxisAlignment: MainAxisAlignment.spaceAround,
          children: [
            Text(widget.deviceID),
            const SizedBox(
              width: 5,
            ),
            ElevatedButton(
                style: ElevatedButton.styleFrom(backgroundColor: Colors.purple),
                onPressed: _isRunning ? null : _print,
                child:
                    Text(_isRunning ? 'Connecting...' : 'Connect and Print')),
          ],
        )));
  }
}

Future<void> _showMyDialog(BuildContext context, String title, body,
    [String okText = "OK", cancelText = "Cancel", bool showCancel = false]) {
  return showDialog<String>(
    context: context,
    builder: (BuildContext context) => AlertDialog(
      title: Text(title),
      content: Text(body),
      actions: [
        Visibility(
            visible: showCancel,
            child: TextButton(
              onPressed: () => Navigator.pop(context, cancelText),
              child: Text(cancelText),
            )),
        TextButton(
          onPressed: () => Navigator.pop(context, okText),
          child: Text(okText),
        ),
      ],
    ),
  );
}

更多关于Flutter扩展打印机功能插件sunmi_ext_printer的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter扩展打印机功能插件sunmi_ext_printer的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


sunmi_ext_printer 是一个用于在 Flutter 应用程序中与商米(Sunmi)打印机进行交互的插件。它允许开发者通过 Flutter 应用程序控制商米打印机的打印功能,例如打印文本、图像、条形码等。

以下是如何在 Flutter 项目中使用 sunmi_ext_printer 插件的基本步骤:

1. 添加依赖

首先,在 pubspec.yaml 文件中添加 sunmi_ext_printer 插件的依赖:

dependencies:
  flutter:
    sdk: flutter
  sunmi_ext_printer: ^1.0.0  # 请根据实际情况使用最新版本

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

2. 初始化打印机

在使用打印机之前,需要先初始化打印机。你可以在应用程序启动时或需要使用打印机时进行初始化。

import 'package:sunmi_ext_printer/sunmi_ext_printer.dart';

void initPrinter() async {
  bool isPrinterReady = await SunmiExtPrinter.initPrinter();
  if (isPrinterReady) {
    print("Printer initialized successfully");
  } else {
    print("Failed to initialize printer");
  }
}

3. 打印文本

初始化打印机后,你可以使用 printText 方法打印文本。

void printText() async {
  bool isPrinted = await SunmiExtPrinter.printText("Hello, World!");
  if (isPrinted) {
    print("Text printed successfully");
  } else {
    print("Failed to print text");
  }
}

4. 打印图像

你还可以使用 printImage 方法打印图像。图像需要转换为 Uint8List 格式。

import 'dart:typed_data';
import 'package:flutter/services.dart';

void printImage(String imagePath) async {
  ByteData imageData = await rootBundle.load(imagePath);
  Uint8List imageBytes = imageData.buffer.asUint8List();
  bool isImagePrinted = await SunmiExtPrinter.printImage(imageBytes);
  if (isImagePrinted) {
    print("Image printed successfully");
  } else {
    print("Failed to print image");
  }
}

5. 打印条形码

使用 printBarcode 方法可以打印条形码。

void printBarcode(String barcode) async {
  bool isBarcodePrinted = await SunmiExtPrinter.printBarcode(barcode);
  if (isBarcodePrinted) {
    print("Barcode printed successfully");
  } else {
    print("Failed to print barcode");
  }
}

6. 切纸

打印完成后,你可以使用 cutPaper 方法进行切纸操作。

void cutPaper() async {
  bool isPaperCut = await SunmiExtPrinter.cutPaper();
  if (isPaperCut) {
    print("Paper cut successfully");
  } else {
    print("Failed to cut paper");
  }
}

7. 设置打印样式

你可以设置文本的字体、对齐方式、大小等样式。

void setPrintStyle() async {
  await SunmiExtPrinter.setAlign(SunmiExtPrinterAlign.CENTER);
  await SunmiExtPrinter.setFontSize(24);
  await SunmiExtPrinter.setBold(true);
}

8. 清理资源

在不再使用打印机时,可以调用 destroyPrinter 方法来释放资源。

void destroyPrinter() async {
  bool isDestroyed = await SunmiExtPrinter.destroyPrinter();
  if (isDestroyed) {
    print("Printer resources released");
  } else {
    print("Failed to release printer resources");
  }
}

9. 错误处理

在实际使用中,可能会遇到打印失败的情况。你可以通过捕获异常来处理这些错误。

void printWithErrorHandling() async {
  try {
    await SunmiExtPrinter.printText("Hello, World!");
  } catch (e) {
    print("Failed to print: $e");
  }
}
回到顶部