paint-brush
Cree una aplicación que imprima desde una impresora térmica Bluetooth usando Flutterpor@altynberg
22,654 lecturas
22,654 lecturas

Cree una aplicación que imprima desde una impresora térmica Bluetooth usando Flutter

por Altynbek Usenbekov2022/01/24
Read on Terminal Reader
Read this story w/o Javascript

Demasiado Largo; Para Leer

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 y esc_pos_utils. Usaremos este complemento para conectar el 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. Podemos escanear y obtener dispositivos disponibles como este: FlutterBlue.

Company Mentioned

Mention Thumbnail
featured image - Cree una aplicación que imprima desde una impresora térmica Bluetooth usando Flutter
Altynbek Usenbekov HackerNoon profile picture


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 flutter_blue y realice la configuración de acuerdo con las instrucciones.

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

  1. Podemos mostrar la lista de dispositivos.
  2. 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 .

  1. Primero, nos conectamos al dispositivo dado.
  2. El Generator es una clase del complemento esc_pos_utils . Con la ayuda de esta clase, podemos crear comandos ESC/POS como este: generator.text('Hello') .
  3. Podemos agregar estos comandos generados a la instancia de BluePrint (crearemos esta clase más adelante).
  4. 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.


  • void add(List<int> data) - Para agregar comandos.
  • List<List<int>> getChunks() : 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.
  • printData(BluetoothDevice device) : envía datos fragmentados al dispositivo a través de BluetoothCharacteristic.


 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 POS de Alto . 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.


El proyecto GitHub está disponible aquí: https://github.com/usenbekov/blue-thermal-printing