Flutter蓝牙热敏打印机插件rt_bluetooth_thermal_printer的使用

Flutter蓝牙热敏打印机插件rt_bluetooth_thermal_printer的使用

简介

rt_bluetooth_thermal_printer 是一个用于通过蓝牙打印收据的 Flutter 插件(仅支持 Android)。它支持 58mm 和 80mm 的蓝牙打印机。

该插件不依赖位置权限,因此遵循 Google 对 Android 10 的政策。

添加依赖项

pubspec.yaml 文件中添加以下依赖项:

dependencies:
  rt_bluetooth_thermal_printer: ^最新版本号
  esc_pos_utils: ^最新版本号

使用示例

示例代码

以下是完整的示例代码,展示如何使用 rt_bluetooth_thermal_printer 插件进行蓝牙热敏打印机的连接和打印。

main.dart

import 'dart:async';

import 'package:rt_bluetooth_thermal_printer/bluetooth_thermal_printer.dart';
import 'package:esc_pos_utils/esc_pos_utils.dart';
import 'package:flutter/material.dart';

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

class MyApp extends StatefulWidget {
  [@override](/user/override)
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  [@override](/user/override)
  void initState() {
    super.initState();
  }

  bool connected = false;
  List availableBluetoothDevices = [];

  Future<void> getBluetooth() async {
    final List bluetooths = await BluetoothThermalPrinter.getBluetooths;
    print("Print $bluetooths");
    setState(() {
      availableBluetoothDevices = bluetooths;
    });
  }

  Future<void> setConnect(String mac) async {
    final String result = await BluetoothThermalPrinter.connect(mac);
    print("state connected $result");
    if (result == "true") {
      setState(() {
        connected = true;
      });
    }
  }

  Future<void> printTicket() async {
    String isConnected = await BluetoothThermalPrinter.connectionStatus;
    if (isConnected == "true") {
      List<int> bytes = await getTicket();
      final result = await BluetoothThermalPrinter.writeBytes(bytes);
      print("Print $result");
    } else {
      // Handle Not Connected Scenario
    }
  }

  Future<void> printGraphics() async {
    String isConnected = await BluetoothThermalPrinter.connectionStatus;
    if (isConnected == "true") {
      List<int> bytes = await getGraphicsTicket();
      final result = await BluetoothThermalPrinter.writeBytes(bytes);
      print("Print $result");
    } else {
      // Handle Not Connected Scenario
    }
  }

  Future<List<int>> getGraphicsTicket() async {
    List<int> bytes = [];

    CapabilityProfile profile = await CapabilityProfile.load();
    final generator = Generator(PaperSize.mm80, profile);

    // Print QR Code using native function
    bytes += generator.qrcode('example.com');

    bytes += generator.hr();

    // Print Barcode using native function
    final List<int> barData = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 4];
    bytes += generator.barcode(Barcode.upcA(barData));

    bytes += generator.cut();

    return bytes;
  }

  Future<List<int>> getTicket() async {
    List<int> bytes = [];
    CapabilityProfile profile = await CapabilityProfile.load();
    final generator = Generator(PaperSize.mm80, profile);

    bytes += generator.text("Demo Shop",
        styles: PosStyles(
          align: PosAlign.center,
          height: PosTextSize.size2,
          width: PosTextSize.size2,
        ),
        linesAfter: 1);

    bytes += generator.text(
        "18th Main Road, 2nd Phase, J. P. Nagar, Bengaluru, Karnataka 560078",
        styles: PosStyles(align: PosAlign.center));
    bytes += generator.text('Tel: +919591708470',
        styles: PosStyles(align: PosAlign.center));

    bytes += generator.hr();
    bytes += generator.row([
      PosColumn(
          text: 'No',
          width: 1,
          styles: PosStyles(align: PosAlign.left, bold: true)),
      PosColumn(
          text: 'Item',
          width: 5,
          styles: PosStyles(align: PosAlign.left, bold: true)),
      PosColumn(
          text: 'Price',
          width: 2,
          styles: PosStyles(align: PosAlign.center, bold: true)),
      PosColumn(
          text: 'Qty',
          width: 2,
          styles: PosStyles(align: PosAlign.center, bold: true)),
      PosColumn(
          text: 'Total',
          width: 2,
          styles: PosStyles(align: PosAlign.right, bold: true)),
    ]);

    bytes += generator.row([
      PosColumn(text: "1", width: 1),
      PosColumn(
          text: "Tea",
          width: 5,
          styles: PosStyles(
            align: PosAlign.left,
          )),
      PosColumn(
          text: "10",
          width: 2,
          styles: PosStyles(
            align: PosAlign.center,
          )),
      PosColumn(text: "1", width: 2, styles: PosStyles(align: PosAlign.center)),
      PosColumn(text: "10", width: 2, styles: PosStyles(align: PosAlign.right)),
    ]);

    bytes += generator.row([
      PosColumn(text: "2", width: 1),
      PosColumn(
          text: "Sada Dosa",
          width: 5,
          styles: PosStyles(
            align: PosAlign.left,
          )),
      PosColumn(
          text: "30",
          width: 2,
          styles: PosStyles(
            align: PosAlign.center,
          )),
      PosColumn(text: "1", width: 2, styles: PosStyles(align: PosAlign.center)),
      PosColumn(text: "30", width: 2, styles: PosStyles(align: PosAlign.right)),
    ]);

    bytes += generator.row([
      PosColumn(text: "3", width: 1),
      PosColumn(
          text: "Masala Dosa",
          width: 5,
          styles: PosStyles(
            align: PosAlign.left,
          )),
      PosColumn(
          text: "50",
          width: 2,
          styles: PosStyles(
            align: PosAlign.center,
          )),
      PosColumn(text: "1", width: 2, styles: PosStyles(align: PosAlign.center)),
      PosColumn(text: "50", width: 2, styles: PosStyles(align: PosAlign.right)),
    ]);

    bytes += generator.row([
      PosColumn(text: "4", width: 1),
      PosColumn(
          text: "Rova Dosa",
          width: 5,
          styles: PosStyles(
            align: PosAlign.left,
          )),
      PosColumn(
          text: "70",
          width: 2,
          styles: PosStyles(
            align: PosAlign.center,
          )),
      PosColumn(text: "1", width: 2, styles: PosStyles(align: PosAlign.center)),
      PosColumn(text: "70", width: 2, styles: PosStyles(align: PosAlign.right)),
    ]);

    bytes += generator.hr();

    bytes += generator.row([
      PosColumn(
          text: 'TOTAL',
          width: 6,
          styles: PosStyles(
            align: PosAlign.left,
            height: PosTextSize.size4,
            width: PosTextSize.size4,
          )),
      PosColumn(
          text: "160",
          width: 6,
          styles: PosStyles(
            align: PosAlign.right,
            height: PosTextSize.size4,
            width: PosTextSize.size4,
          )),
    ]);

    bytes += generator.hr(ch: '=', linesAfter: 1);

    // ticket.feed(2);
    bytes += generator.text('Thank you!',
        styles: PosStyles(align: PosAlign.center, bold: true));

    bytes += generator.text("26-11-2020 15:22:45",
        styles: PosStyles(align: PosAlign.center), linesAfter: 1);

    bytes += generator.text(
        'Note: Goods once sold will not be taken back or exchanged.',
        styles: PosStyles(align: PosAlign.center, bold: false));
    bytes += generator.cut();
    return bytes;
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Bluetooth Thermal Printer Demo'),
        ),
        body: Container(
          padding: EdgeInsets.all(20),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              Text("Search Paired Bluetooth"),
              TextButton(
                onPressed: () {
                  this.getBluetooth();
                },
                child: Text("Search"),
              ),
              Container(
                height: 200,
                child: ListView.builder(
                  itemCount: availableBluetoothDevices.length > 0
                      ? availableBluetoothDevices.length
                      : 0,
                  itemBuilder: (context, index) {
                    return ListTile(
                      onTap: () {
                        String select = availableBluetoothDevices[index];
                        List list = select.split("#");
                        // String name = list[0];
                        String mac = list[1];
                        this.setConnect(mac);
                      },
                      title: Text('${availableBluetoothDevices[index]}'),
                      subtitle: Text("Click to connect"),
                    );
                  },
                ),
              ),
              SizedBox(
                height: 30,
              ),
              TextButton(
                onPressed: connected ? this.printGraphics : null,
                child: Text("Print"),
              ),
              TextButton(
                onPressed: connected ? this.printTicket : null,
                child: Text("Print Ticket"),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

更多关于Flutter蓝牙热敏打印机插件rt_bluetooth_thermal_printer的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter蓝牙热敏打印机插件rt_bluetooth_thermal_printer的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


rt_bluetooth_thermal_printer 是一个用于 Flutter 的插件,它允许你通过蓝牙连接热敏打印机并发送打印任务。以下是如何使用这个插件的基本步骤:

1. 添加依赖

首先,你需要在 pubspec.yaml 文件中添加 rt_bluetooth_thermal_printer 插件的依赖:

dependencies:
  flutter:
    sdk: flutter
  rt_bluetooth_thermal_printer: ^1.0.0  # 请使用最新版本

然后运行 flutter pub get 来获取依赖。

2. 导入插件

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

import 'package:rt_bluetooth_thermal_printer/rt_bluetooth_thermal_printer.dart';

3. 初始化插件

在使用插件之前,你需要初始化它:

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

4. 扫描并连接蓝牙设备

你可以使用 scan 方法来扫描附近的蓝牙设备,并使用 connect 方法来连接打印机:

void scanAndConnect() async {
  List<BluetoothDevice> devices = await RtBluetoothThermalPrinter.scan();
  
  if (devices.isNotEmpty) {
    BluetoothDevice printer = devices.first; // 选择第一个设备
    bool isConnected = await RtBluetoothThermalPrinter.connect(printer);
    
    if (isConnected) {
      print("Connected to printer: ${printer.name}");
    } else {
      print("Failed to connect to printer");
    }
  } else {
    print("No devices found");
  }
}

5. 打印文本

连接成功后,你可以使用 printText 方法来打印文本:

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

6. 打印自定义内容

你还可以使用 printCustom 方法来打印自定义内容,比如图片、条形码等:

void printCustom() async {
  String customContent = "Custom content to print";
  bool isPrinted = await RtBluetoothThermalPrinter.printCustom(customContent);
  
  if (isPrinted) {
    print("Custom content printed successfully");
  } else {
    print("Failed to print custom content");
  }
}

7. 断开连接

打印完成后,记得断开与打印机的连接:

void disconnectPrinter() async {
  bool isDisconnected = await RtBluetoothThermalPrinter.disconnect();
  
  if (isDisconnected) {
    print("Printer disconnected successfully");
  } else {
    print("Failed to disconnect printer");
  }
}

8. 处理权限

在 Android 上,你需要确保应用具有蓝牙和位置权限。你可以在 AndroidManifest.xml 中添加以下权限:

<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>

并在运行时请求这些权限。

9. 处理错误

在实际使用中,你可能会遇到各种错误,比如连接失败、打印失败等。确保你正确处理这些错误,并提供适当的用户反馈。

10. 示例代码

以下是一个完整的示例代码,展示了如何使用 rt_bluetooth_thermal_printer 插件:

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

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

class MyApp extends StatelessWidget {
  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      home: PrinterScreen(),
    );
  }
}

class PrinterScreen extends StatefulWidget {
  [@override](/user/override)
  _PrinterScreenState createState() => _PrinterScreenState();
}

class _PrinterScreenState extends State<PrinterScreen> {
  [@override](/user/override)
  void initState() {
    super.initState();
    initPrinter();
  }

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

  void scanAndConnect() async {
    List<BluetoothDevice> devices = await RtBluetoothThermalPrinter.scan();
    
    if (devices.isNotEmpty) {
      BluetoothDevice printer = devices.first; // 选择第一个设备
      bool isConnected = await RtBluetoothThermalPrinter.connect(printer);
      
      if (isConnected) {
        print("Connected to printer: ${printer.name}");
      } else {
        print("Failed to connect to printer");
      }
    } else {
      print("No devices found");
    }
  }

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

  void disconnectPrinter() async {
    bool isDisconnected = await RtBluetoothThermalPrinter.disconnect();
    
    if (isDisconnected) {
      print("Printer disconnected successfully");
    } else {
      print("Failed to disconnect printer");
    }
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Bluetooth Thermal Printer"),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            ElevatedButton(
              onPressed: scanAndConnect,
              child: Text("Scan and Connect"),
            ),
            ElevatedButton(
              onPressed: printText,
              child: Text("Print Text"),
            ),
            ElevatedButton(
              onPressed: disconnectPrinter,
              child: Text("Disconnect Printer"),
            ),
          ],
        ),
      ),
    );
  }
}
回到顶部