Flutter实现蓝牙打印的方法及跨平台蓝牙打印方案咨询
在Flutter中实现蓝牙打印字符串的方案
刚好我做过类似的跨平台迁移项目,把安卓端的蓝牙打印模块转到Flutter同时支持iOS,给你分享下实际可行的方案和思路:
首先明确说:Flutter完全支持蓝牙打印功能,只是没有官方内置的API,咱们主要依靠成熟的第三方插件就能搞定,完美匹配你从安卓迁移到跨平台的需求。
一、主流第三方插件方案(优先推荐)
社区里目前用得最多的是两款插件,各有侧重,你可以根据打印需求选择:
1. esc_pos_bluetooth(适合小票/收据类打印)
这个插件专门针对ESC/POS格式的热敏打印机——大部分商用小票打印机都支持这个格式,对Android和iOS的兼容性都很稳定。
步骤1:添加依赖
在项目的pubspec.yaml中加入:
dependencies: esc_pos_bluetooth: ^0.2.8 # 建议用pub上的最新版本 flutter_blue_plus: ^1.13.3 # 依赖的蓝牙扫描核心库
步骤2:配置平台权限
- Android端:在
AndroidManifest.xml中添加对应权限(根据系统版本区分):
<!-- Android 11及以下版本 --> <uses-permission android:name="android.permission.BLUETOOTH" /> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <!-- Android 12+版本 --> <uses-permission android:name="android.permission.BLUETOOTH_SCAN" android:usesPermissionFlags="neverForLocation" /> <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
- iOS端:在
Info.plist中添加蓝牙权限描述:
<key>NSBluetoothAlwaysUsageDescription</key> <string>需要蓝牙权限连接打印机,完成单据打印</string> <key>NSBluetoothPeripheralUsageDescription</key> <string>需要蓝牙权限连接打印机,完成单据打印</string>
步骤3:核心代码示例
import 'package:esc_pos_bluetooth/esc_pos_bluetooth.dart'; import 'package:flutter_blue_plus/flutter_blue_plus.dart'; // 扫描周边蓝牙打印机 Future<List<BluetoothDevice>> scanPrinters() async { List<BluetoothDevice> availablePrinters = []; // 启动扫描,超时4秒 FlutterBluePlus.startScan(timeout: const Duration(seconds: 4)); // 监听扫描结果 FlutterBluePlus.scanResults.listen((results) { for (ScanResult result in results) { if (!availablePrinters.contains(result.device)) { availablePrinters.add(result.device); } } }); await Future.delayed(const Duration(seconds: 4)); FlutterBluePlus.stopScan(); return availablePrinters; } // 连接打印机并打印字符串内容 Future<void> printContent(BluetoothDevice targetPrinter) async { final printerManager = PrinterBluetoothManager(); try { // 连接目标打印机 await printerManager.connect(targetPrinter); // 构建打印内容(支持文本样式、换行、切纸等) final List<int> printBytes = []; final generator = Generator(PaperSize.mm80); // 添加需要打印的字符串 printBytes.addAll(generator.text('公司收据')); printBytes.addAll(generator.text('订单编号: NO.20240520001', styles: const PosStyles(bold: true))); printBytes.addAll(generator.text('------------------------')); printBytes.addAll(generator.text('打印时间: ${DateTime.now().toString().substring(0, 19)}')); printBytes.addAll(generator.feed(2)); // 空两行 printBytes.addAll(generator.cut()); // 发送切纸指令 // 发送打印数据 await printerManager.printBytes(printBytes); print('打印成功'); } catch (e) { print('打印失败: ${e.toString()}'); } finally { // 断开连接 printerManager.disconnect(); } }
2. blue_thermal_printer
这个插件API更简洁,适合打印内容简单的场景,集成速度快,但对复杂格式的支持不如esc_pos_bluetooth,如果你的打印需求只是简单文本输出,可以考虑这个。
二、替代方案:自定义平台通道(Platform Channel)
如果第三方插件满足不了你的定制需求(比如要支持特殊打印机协议、自定义蓝牙通信逻辑),可以用Flutter的平台通道自己开发原生逻辑:
- Android端:利用原生的
BluetoothAdapter和BluetoothSocket实现蓝牙连接与数据发送,通过MethodChannel和Flutter交互。 - iOS端:使用CoreBluetooth框架搜索外设、建立连接、发送打印指令,同样通过MethodChannel和Flutter通信。
这种方式灵活性最高,但需要你熟悉Android和iOS的原生蓝牙开发,适合有原生开发经验的团队。
三、注意事项
- 测试时尽量用真实打印机,模拟器基本不支持蓝牙功能。
- 不同打印机的ESC/POS指令可能略有差异,如果出现乱码,可以尝试调整字符编码(比如切换为
GBK或UTF-8)。 - Android 12+的蓝牙权限需要动态申请,记得在代码中处理权限弹窗逻辑。
内容的提问来源于stack exchange,提问作者Gökhan Aldanmaz




