Hoy vamos a aprender a imprimir a través de la impresora térmica Bluetooth en Flutter. Para lograr esto, debemos conectarnos a una impresora a través de Bluetooth y enviar datos imprimibles como texto, imagen o código QR. Usaremos estos complementos: flutter_blue: ^0.8.0 esc_pos_utils: ^1.1.0 aleteo_azul Usaremos este complemento para conectarnos al dispositivo Bluetooth y enviar los datos. No es solo para impresoras térmicas, sino que también se puede usar para cualquier dispositivo Bluetooth. Elegí este complemento porque es compatible con iOS, Android y macOS. https://pub.dev/packages/flutter_blue esc_pos_utils Este complemento ayudará a generar comandos ESC/POS para enviarlos a través de flutter_blue. Admite imágenes, códigos de barras, estilo de texto, tablas, corte de papel, alimentación de papel y mucho más. https://pub.dev/packages/esc_pos_utils Configuración Es posible que necesitemos configuraciones de permisos, así que vaya a la página y realice la configuración de acuerdo con las instrucciones. flutter_blue Buscar dispositivos Podemos escanear y obtener dispositivos disponibles como este: FlutterBlue flutterBlue = FlutterBlue.instance; // Start scanning flutterBlue.startScan(timeout: Duration(seconds: 4)); // Listen to scan results var subscription = flutterBlue.scanResults.listen((results) { // do something with scan results for (ScanResult r in results) { print('${r.device.name} found! rssi: ${r.rssi}'); } }); // Stop scanning flutterBlue.stopScan(); Pero vamos a crear un widget donde Podemos mostrar la lista de dispositivos. Y cuando se selecciona un dispositivo, genera comandos ESC/POS y los envía al dispositivo seleccionado. import 'package:blue_thermal_printing/blue_print.dart'; import 'package:esc_pos_utils/esc_pos_utils.dart'; import 'package:flutter/material.dart'; import 'package:flutter_blue/flutter_blue.dart'; FlutterBlue flutterBlue = FlutterBlue.instance; class PrintingWidget extends StatefulWidget { const PrintingWidget({Key? key}) : super(key: key); @override _PrintingWidgetState createState() => _PrintingWidgetState(); } class _PrintingWidgetState extends State<PrintingWidget> { List<ScanResult>? scanResult; @override void initState() { super.initState(); findDevices(); } void findDevices() { flutterBlue.startScan(timeout: const Duration(seconds: 4)); flutterBlue.scanResults.listen((results) { setState(() { scanResult = results; }); }); flutterBlue.stopScan(); } void printWithDevice(BluetoothDevice device) async { await device.connect(); final gen = Generator(PaperSize.mm58, await CapabilityProfile.load()); final printer = BluePrint(); printer.add(gen.qrcode('https://altospos.com')); printer.add(gen.text('Hello')); printer.add(gen.text('World', styles: const PosStyles(bold: true))); printer.add(gen.feed(1)); await printer.printData(device); device.disconnect(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('Bluetooth devices')), body: ListView.separated( itemBuilder: (context, index) { return ListTile( title: Text(scanResult![index].device.name), subtitle: Text(scanResult![index].device.id.id), onTap: () => printWithDevice(scanResult![index].device), ); }, separatorBuilder: (context, index) => const Divider(), itemCount: scanResult?.length ?? 0, ), ); } } Veamos el método . printWithDevice Primero, nos conectamos al dispositivo dado. El es una clase del complemento . Con la ayuda de esta clase, podemos crear comandos ESC/POS como este: . Generator esc_pos_utils generator.text('Hello') Podemos agregar estos comandos generados a la instancia de (crearemos esta clase más adelante). BluePrint Al finalizar, enviamos todos los datos generados a la impresora Bluetooth y desconectamos al terminar. Impresión Ahora veamos la clase BluePrint. En resumen, recopila comandos ESC/POS y envía estos datos a una impresora determinada. - Para agregar comandos. void add(List<int> data) : si necesitamos imprimir datos muy grandes como una imagen, podemos encontrar problemas porque algunos dispositivos fallarán debido al gran tamaño del paquete. Así que tenemos que enviar los datos en trozos. List<List<int>> getChunks() : envía datos fragmentados al dispositivo a través de BluetoothCharacteristic. printData(BluetoothDevice device) import 'dart:math'; import 'package:flutter_blue/flutter_blue.dart'; class BluePrint { BluePrint({this.chunkLen = 512}); final int chunkLen; final _data = List<int>.empty(growable: true); void add(List<int> data) { _data.addAll(data); } List<List<int>> getChunks() { final chunks = List<List<int>>.empty(growable: true); for (var i = 0; i < _data.length; i += chunkLen) { chunks.add(_data.sublist(i, min(i + chunkLen, _data.length))); } return chunks; } Future<void> printData(BluetoothDevice device) async { final data = getChunks(); final characs = await _getCharacteristics(device); for (var i = 0; i < characs.length; i++) { if (await _tryPrint(characs[i], data)) { break; } } } Future<bool> _tryPrint( BluetoothCharacteristic charac, List<List<int>> data, ) async { for (var i = 0; i < data.length; i++) { try { await charac.write(data[i]); } catch (e) { return false; } } return true; } Future<List<BluetoothCharacteristic>> _getCharacteristics( BluetoothDevice device, ) async { final services = await device.discoverServices(); final res = List<BluetoothCharacteristic>.empty(growable: true); for (var i = 0; i < services.length; i++) { res.addAll(services[i].characteristics); } return res; } } Necesitaba agregar una función de impresora térmica Bluetooth cuando estaba trabajando en el proyecto . Fue mi primera experiencia con Bluetooth con Flutter y, debido al poco material que contenía, tuve que probar muchas cosas antes de que funcionara correctamente en todos los dispositivos. Así que decidí escribir este artículo con la esperanza de que sea útil para otros. POS de Alto El proyecto GitHub está disponible aquí: https://github.com/usenbekov/blue-thermal-printing