Flutter蓝牙打印插件blue_print_pos_plus的使用

Flutter蓝牙打印插件blue_print_pos_plus的使用

简介

本插件用于在Android/iOS上使用蓝牙打印机。支持文本、图像、添加换行或虚线和二维码。

使用

初始化

BluePrintPos bluePrintPos = BluePrintPos.instance; 

扫描蓝牙打印机

bluePrintPos.scan();

连接蓝牙打印机

bluePrintPos.connect(device);

打印文本

在方法 addText(text, {size, style, alignment}) 中可以修改大小、样式和对齐方式。

ReceiptSectionText receiptText = ReceiptSectionText();
receiptText.addText('MY STORE', size: ReceiptTextSizeType.medium, style: ReceiptTextStyleType.bold);

打印文本左对齐和右对齐

receiptText.addLeftRightText('Time', '04/06/21, 10:00');

打印图像

final ByteData logoBytes = await rootBundle.load('assets/logo.jpg');
receiptText.addImage(
  base64.encode(Uint8List.view(logoBytes.buffer)),
  width: 150,
);

添加新行

receiptText.addSpacer();

添加带虚线的新行

receiptText.addSpacer(useDashed: true);

入门指南

Android

minSdkVersionandroid/app/build.gradle 文件中更改为19。

android {
  defaultConfig {
     minSdkVersion 19
  }
}

android/app/src/main/AndroidManifest.xml 文件中添加蓝牙和位置访问权限。

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

iOS

ios/Runner/Info.plist 文件中添加信息键。

<key>NSBluetoothAlwaysUsageDescription</key>  
<string>Need BLE permission</string>  
<key>NSBluetoothPeripheralUsageDescription</key>  
<string>Need BLE permission</string>  
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>  
<string>Need Location permission</string>  
<key>NSLocationAlwaysUsageDescription</key>  
<string>Need Location permission</string>  
<key>NSLocationWhenInUseUsageDescription</key>  
<string>Need Location permission</string>

感谢

参考和依赖此插件的项目:


完整示例

以下是一个完整的示例,展示了如何使用 blue_print_pos_plus 插件进行蓝牙打印。

import 'dart:convert';
import 'dart:typed_data';

import 'package:blue_print_pos_plus/blue_print_pos.dart';
import 'package:blue_print_pos_plus/models/models.dart';
import 'package:blue_print_pos_plus/receipt/receipt.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

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

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

class _MyAppState extends State<MyApp> {
  final BluePrintPos _bluePrintPos = BluePrintPos.instance;
  List<BlueDevice> _blueDevices = [];
  BlueDevice? _selectedDevice;
  bool _isLoading = false;
  int _loadingAtIndex = -1;

  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Blue Print Pos'),
        ),
        body: SafeArea(
          child: _isLoading && _blueDevices.isEmpty
              ? const Center(
                  child: CircularProgressIndicator(
                    valueColor: AlwaysStoppedAnimation<Color>(Colors.blue),
                  ),
                )
              : _blueDevices.isNotEmpty
                  ? SingleChildScrollView(
                      child: Column(
                        crossAxisAlignment: CrossAxisAlignment.start,
                        children: [
                          Column(
                            children: List.generate(_blueDevices.length, (int index) {
                              return Row(
                                children: [
                                  Expanded(
                                    child: GestureDetector(
                                      onTap: _blueDevices[index].address == (_selectedDevice?.address ?? '')
                                          ? _onDisconnectDevice
                                          : () => _onSelectDevice(index),
                                      child: Padding(
                                        padding: const EdgeInsets.all(8.0),
                                        child: Column(
                                          crossAxisAlignment: CrossAxisAlignment.start,
                                          children: [
                                            Text(
                                              _blueDevices[index].name,
                                              style: TextStyle(
                                                color: _selectedDevice?.address == _blueDevices[index].address
                                                    ? Colors.blue
                                                    : Colors.black,
                                                fontSize: 20,
                                                fontWeight: FontWeight.w500,
                                              ),
                                            ),
                                            Text(
                                              _blueDevices[index].address,
                                              style: TextStyle(
                                                color: _selectedDevice?.address == _blueDevices[index].address
                                                    ? Colors.blueGrey
                                                    : Colors.grey,
                                                fontSize: 14,
                                                fontWeight: FontWeight.w500,
                                              ),
                                            ),
                                          ],
                                        ),
                                      ),
                                    ),
                                  ),
                                  if (_loadingAtIndex == index && _isLoading)
                                    Container(
                                      height: 24.0,
                                      width: 24.0,
                                      margin: const EdgeInsets.only(right: 8.0),
                                      child: const CircularProgressIndicator(
                                        valueColor: AlwaysStoppedAnimation<Color>(
                                          Colors.blue,
                                        ),
                                      ),
                                    ),
                                  if (!_isLoading && _blueDevices[index].address == (_selectedDevice?.address ?? ''))
                                    TextButton(
                                      onPressed: _onPrintReceipt,
                                      child: Container(
                                        color: _selectedDevice == null
                                            ? Colors.grey
                                            : Colors.blue,
                                        padding: const EdgeInsets.all(8.0),
                                        child: const Text(
                                          'Test Print',
                                          style: TextStyle(color: Colors.white),
                                        ),
                                      ),
                                      style: ButtonStyle(
                                        backgroundColor: MaterialStateProperty.resolveWith<Color>(
                                          (Set<MaterialState> states) {
                                            if (states.contains(MaterialState.pressed)) {
                                              return Theme.of(context).colorScheme.primary.withOpacity(0.5);
                                            }
                                            return Theme.of(context).primaryColor;
                                          },
                                        ),
                                      ),
                                    ),
                                ],
                              );
                            }),
                          ),
                        ],
                      ),
                    )
                  : Center(
                      child: Column(
                        mainAxisAlignment: MainAxisAlignment.center,
                        children: const [
                          Text(
                            'Scan bluetooth device',
                            style: TextStyle(fontSize: 24, color: Colors.blue),
                          ),
                          Text(
                            'Press button scan',
                            style: TextStyle(fontSize: 14, color: Colors.grey),
                          ),
                        ],
                      ),
                    ),
        ),
        floatingActionButton: FloatingActionButton(
          onPressed: _isLoading ? null : _onScanPressed,
          child: const Icon(Icons.search),
          backgroundColor: _isLoading ? Colors.grey : Colors.blue,
        ),
      ),
    );
  }

  Future<void> _onScanPressed() async {
    setState(() => _isLoading = true);
    _bluePrintPos.scan().then((List<BlueDevice> devices) {
      if (devices.isNotEmpty) {
        setState(() {
          _blueDevices = devices;
          _isLoading = false;
        });
      } else {
        setState(() => _isLoading = false);
      }
    });
  }

  void _onDisconnectDevice() {
    _bluePrintPos.disconnect().then((ConnectionStatus status) {
      if (status == ConnectionStatus.disconnect) {
        setState(() {
          _selectedDevice = null;
        });
      }
    });
  }

  void _onSelectDevice(int index) {
    setState(() {
      _isLoading = true;
      _loadingAtIndex = index;
    });
    final BlueDevice blueDevice = _blueDevices[index];
    _bluePrintPos.connect(blueDevice).then((ConnectionStatus status) {
      if (status == ConnectionStatus.connected) {
        setState(() => _selectedDevice = blueDevice);
      } else if (status == ConnectionStatus.timeout) {
        _onDisconnectDevice();
      } else {
        print('$runtimeType - something wrong');
      }
      setState(() => _isLoading = false);
    });
  }

  Future<void> _onPrintReceipt() async {
    /// Example for Print Image
    final ByteData logoBytes = await rootBundle.load(
      'assets/logo.jpg',
    );

    /// Example for Print Text
    final ReceiptSectionText receiptText = ReceiptSectionText();
    receiptText.addImage(
      base64.encode(Uint8List.view(logoBytes.buffer)),
      width: 150,
    );
    receiptText.addSpacer();
    receiptText.addText(
      'MY STORE',
      size: ReceiptTextSizeType.medium,
      style: ReceiptTextStyleType.bold,
    );
    receiptText.addText(
      'Black White Street, Jakarta, Indonesia',
      size: ReceiptTextSizeType.small,
    );
    receiptText.addSpacer(useDashed: true);
    receiptText.addLeftRightText('Time', '04/06/21, 10:00');
    receiptText.addSpacer(useDashed: true);
    receiptText.addLeftRightText(
      'Apple 1kg',
      'Rp30.000',
      leftStyle: ReceiptTextStyleType.normal,
      rightStyle: ReceiptTextStyleType.bold,
    );
    receiptText.addSpacer(useDashed: true);
    receiptText.addLeftRightText(
      'TOTAL',
      'Rp30.000',
      leftStyle: ReceiptTextStyleType.normal,
      rightStyle: ReceiptTextStyleType.bold,
    );
    receiptText.addSpacer(useDashed: true);
    receiptText.addLeftRightText(
      'Payment',
      'Cash',
      leftStyle: ReceiptTextStyleType.normal,
      rightStyle: ReceiptTextStyleType.normal,
    );
    receiptText.addSpacer(count: 2);

    await _bluePrintPos.printReceiptText(receiptText);

    /// Example for print QR
    await _bluePrintPos.printQR('www.google.com', size: 250);

    /// Text after QR
    final ReceiptSectionText receiptSecondText = ReceiptSectionText();
    receiptSecondText.addText('Powered by ayeee',
        size: ReceiptTextSizeType.small);
    receiptSecondText.addSpacer();
    await _bluePrintPos.printReceiptText(receiptSecondText, feedCount: 1);
  }
}

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

1 回复

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


blue_print_pos_plus 是一个用于在 Flutter 应用中通过蓝牙连接并打印小票的插件。以下是如何使用该插件的基本步骤:

1. 添加依赖

首先,在 pubspec.yaml 文件中添加 blue_print_pos_plus 依赖:

dependencies:
  flutter:
    sdk: flutter
  blue_print_pos_plus: ^latest_version

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

2. 配置权限

在 Android 和 iOS 上,你需要配置相应的权限以允许应用访问蓝牙和位置服务。

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"/>

iOS

Info.plist 中添加以下权限:

<key>NSBluetoothAlwaysUsageDescription</key>
<string>我们需要访问蓝牙来连接打印机</string>
<key>NSBluetoothPeripheralUsageDescription</key>
<string>我们需要访问蓝牙来连接打印机</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>我们需要访问位置服务来扫描蓝牙设备</string>

3. 初始化插件

在你的 Dart 代码中导入插件并进行初始化:

import 'package:blue_print_pos_plus/blue_print_pos_plus.dart';

final bluePrintPosPlus = BluePrintPosPlus();

4. 扫描蓝牙设备

使用 scan 方法来扫描附近的蓝牙设备:

List<BluetoothDevice> devices = [];

void scanDevices() async {
  devices = await bluePrintPosPlus.scan();
  // 更新UI以显示扫描到的设备
}

5. 连接蓝牙设备

选择要连接的设备并使用 connect 方法进行连接:

void connectToDevice(BluetoothDevice device) async {
  bool isConnected = await bluePrintPosPlus.connect(device);
  if (isConnected) {
    print("Connected to ${device.name}");
  } else {
    print("Failed to connect");
  }
}

6. 打印小票

使用 print 方法来打印小票。你可以自定义打印内容,例如文本、图像、二维码等:

void printReceipt() async {
  List<int> bytes = await bluePrintPosPlus.print(
    type: PrinterType.bluetooth,
    payload: [
      "Hello, World!",
      "This is a test receipt.",
      "Thank you for using our service.",
    ],
  );

  if (bytes.isNotEmpty) {
    print("Printing successful");
  } else {
    print("Printing failed");
  }
}

7. 断开连接

打印完成后,使用 disconnect 方法断开蓝牙连接:

void disconnectDevice() async {
  await bluePrintPosPlus.disconnect();
  print("Disconnected");
}

8. 处理错误

在实际使用中,可能会遇到各种错误(例如连接失败、打印失败等),因此建议在代码中添加错误处理逻辑。

完整示例

以下是一个简单的完整示例:

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

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

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

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

class _BluetoothPrinterScreenState extends State<BluetoothPrinterScreen> {
  final bluePrintPosPlus = BluePrintPosPlus();
  List<BluetoothDevice> devices = [];
  BluetoothDevice? selectedDevice;

  void scanDevices() async {
    devices = await bluePrintPosPlus.scan();
    setState(() {});
  }

  void connectToDevice(BluetoothDevice device) async {
    bool isConnected = await bluePrintPosPlus.connect(device);
    if (isConnected) {
      setState(() {
        selectedDevice = device;
      });
      print("Connected to ${device.name}");
    } else {
      print("Failed to connect");
    }
  }

  void printReceipt() async {
    if (selectedDevice == null) return;

    List<int> bytes = await bluePrintPosPlus.print(
      type: PrinterType.bluetooth,
      payload: [
        "Hello, World!",
        "This is a test receipt.",
        "Thank you for using our service.",
      ],
    );

    if (bytes.isNotEmpty) {
      print("Printing successful");
    } else {
      print("Printing failed");
    }
  }

  void disconnectDevice() async {
    await bluePrintPosPlus.disconnect();
    setState(() {
      selectedDevice = null;
    });
    print("Disconnected");
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Bluetooth Printer"),
      ),
      body: Column(
        children: [
          ElevatedButton(
            onPressed: scanDevices,
            child: Text("Scan Devices"),
          ),
          Expanded(
            child: ListView.builder(
              itemCount: devices.length,
              itemBuilder: (context, index) {
                return ListTile(
                  title: Text(devices[index].name ?? "Unknown Device"),
                  subtitle: Text(devices[index].address),
                  onTap: () => connectToDevice(devices[index]),
                );
              },
            ),
          ),
          if (selectedDevice != null)
            Column(
              children: [
                Text("Connected to: ${selectedDevice!.name}"),
                ElevatedButton(
                  onPressed: printReceipt,
                  child: Text("Print Receipt"),
                ),
                ElevatedButton(
                  onPressed: disconnectDevice,
                  child: Text("Disconnect"),
                ),
              ],
            ),
        ],
      ),
    );
  }
}
回到顶部