easy_blue_printer 2.2.0
easy_blue_printer: ^2.2.0 copied to clipboard
The **Easy Blue Printer** plugin allows seamless integration of Bluetooth printers in a Flutter app, enabling the scanning, connection, and printing functionality.
Easy Blue Printer #
A Flutter plugin for Bluetooth thermal printers. Scan, connect, and print text or images with just a few lines of code.
English #
Features #
- Scan nearby Bluetooth devices
- Connect and disconnect from printers
- Print text with font size, alignment, and bold options
- Print images from bytes
- Print empty lines (paper feed)
- Check connection status
- Configure paper roll size (58mm, 80mm, or custom) for accurate image printing
- Built-in print queue — sequential, non-concurrent writes with no manual delays needed
- Works on Android and iOS
Supported Platforms #
| Platform | Minimum Version |
|---|---|
| Android | SDK 24 (7.0) |
| iOS | 13.0 |
| Flutter | 3.44.0 |
| Dart | 3.12.0 |
On iOS the plugin ships both a Swift Package (ios/easy_blue_printer/Package.swift) and a
CocoaPods podspec, so it works with either integration — no extra setup required.
On Android the plugin uses Built-in Kotlin: it no longer applies the Kotlin Gradle Plugin,
so it does not trigger the plugins that apply Kotlin Gradle Plugin (KGP) build warning.
Installation #
Add to your pubspec.yaml:
dependencies:
easy_blue_printer: ^latest_version
Then run:
flutter pub get
Platform Setup #
Android #
Add these permissions to android/app/src/main/AndroidManifest.xml:
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
<application ...>
On Android 12+ the plugin automatically requests runtime permissions.
iOS #
Add these keys to ios/Runner/Info.plist:
<key>NSBluetoothAlwaysUsageDescription</key>
<string>This app needs Bluetooth to connect to printers</string>
<key>NSBluetoothPeripheralUsageDescription</key>
<string>This app needs Bluetooth to connect to printers</string>
Quick Start #
import 'package:easy_blue_printer/easy_blue_printer.dart';
final printer = EasyBluePrinter.instance;
// 1. Scan for devices
final devices = await printer.getPairedDevices();
// 2. Connect to a device
final connected = await printer.connectToDevice(devices.first);
// 3. Configure paper roll size (call once after connecting)
await printer.configurePrinter(PaperConfig.roll80mm); // or PaperConfig.roll58mm
// 4. Print text
await printer.printData(
data: 'Hello, World!',
fontSize: FS.medium,
textAlign: TA.center,
bold: true,
);
// 5. Feed paper
await printer.printEmptyLine(callTimes: 5);
// 6. Disconnect
await printer.disconnectFromDevice();
API Reference #
EasyBluePrinter.instance #
Singleton instance. Use this to access all methods.
getPairedDevices() #
Scans and returns a list of available Bluetooth devices.
Future<List<BluetoothDevice>> getPairedDevices()
Returns: List of BluetoothDevice objects with name and address properties.
connectToDevice(device) #
Connects to a Bluetooth printer.
Future<bool> connectToDevice(BluetoothDevice device)
| Parameter | Type | Description |
|---|---|---|
device |
BluetoothDevice |
Device returned by getPairedDevices() |
Returns: true if connected successfully.
disconnectFromDevice() #
Disconnects from the current printer.
Future<bool> disconnectFromDevice()
Returns: true if disconnected successfully.
printData(...) #
Prints formatted text.
Future<bool> printData({
required String data,
required FS fontSize,
required TA textAlign,
required bool bold,
})
| Parameter | Type | Description |
|---|---|---|
data |
String |
Text to print |
fontSize |
FS |
Font size (see Enums) |
textAlign |
TA |
Alignment (see Enums) |
bold |
bool |
Enable bold text |
Returns: true if printed successfully.
printEmptyLine(callTimes) #
Feeds paper by printing empty lines.
Future<void> printEmptyLine({required int callTimes})
| Parameter | Type | Description |
|---|---|---|
callTimes |
int |
Number of empty lines to print |
printImage(bytes, textAlign) #
Prints an image on the thermal printer.
Future<bool> printImage({
required Uint8List bytes,
required TA textAlign,
})
| Parameter | Type | Description |
|---|---|---|
bytes |
Uint8List |
Image data as bytes |
textAlign |
TA |
Image alignment (see Enums) |
Returns: true if printed successfully.
Example — print from assets:
import 'package:flutter/services.dart';
final byteData = await rootBundle.load('assets/images/logo.png');
final bytes = byteData.buffer.asUint8List();
await printer.printImage(bytes: bytes, textAlign: TA.center);
configurePrinter(config) #
Configures the paper roll size used when printing images. Call this once after connecting to the printer.
Future<void> configurePrinter(PaperConfig config)
| Parameter | Type | Description |
|---|---|---|
config |
PaperConfig |
Paper roll configuration |
Example:
// 58mm roll (default)
await printer.configurePrinter(PaperConfig.roll58mm);
// 80mm roll
await printer.configurePrinter(PaperConfig.roll80mm);
// Custom width in pixels
await printer.configurePrinter(PaperConfig(widthPixels: 480));
Only affects
printImage. Text printing is handled by the printer firmware and does not require this configuration.
isConnected() #
Checks if a printer is currently connected.
Future<bool> isConnected()
Returns: true if connected.
commandDelay #
Configurable delay applied between consecutive print commands. The built-in queue already serializes all commands; this delay gives the printer extra time to process each command before the next one arrives.
Duration commandDelay // default: Duration(milliseconds: 100)
Example:
// Increase for slower printers that still show corrupted output
printer.commandDelay = const Duration(milliseconds: 150);
// Disable for fast printers that don't need it
printer.commandDelay = Duration.zero;
Only applies between queued print commands. Does not add latency after the last command in a batch.
Enums #
FS — Font Size #
| Value | Description |
|---|---|
FS.normal |
Normal size |
FS.medium |
Medium size |
FS.large |
Large size |
FS.huge |
Extra large |
TA — Text Alignment #
| Value | Description |
|---|---|
TA.left |
Left align |
TA.center |
Center align |
TA.right |
Right align |
PaperConfig — Paper Roll Size #
| Value / Constructor | Width | Description |
|---|---|---|
PaperConfig.roll58mm |
384 px | 58mm roll (most common, default) |
PaperConfig.roll80mm |
576 px | 80mm roll |
PaperConfig(widthPixels: n) |
custom | Any custom width in pixels |
PrintDensity — Print Darkness #
Optional. Controls how much the thermal head heats each dot (ESC 7). More heat darkens the
stroke and makes small text and barcodes easier to read, at the cost of printing slightly slower
and wearing the head faster.
| Value | Heating time | Description |
|---|---|---|
| omitted (default) | — | Sends no command; keeps the printer's factory value |
PrintDensity.normal |
80 | Factory default of most thermal printers |
PrintDensity.dark |
120 | One step darker — usually fixes faded small text |
PrintDensity.darkest |
160 | Practical limit before the stroke starts to blur |
// Darker print on an 80mm roll
await printer.configurePrinter(
PaperConfig.roll80mm.copyWith(density: PrintDensity.dark),
);
Not every printer implements
ESC 7. Most that don't simply ignore it, but a few print the parameters as text — that is why nothing is sent unless you ask for a density.
Complete Example #
import 'package:easy_blue_printer/easy_blue_printer.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(home: const PrinterPage());
}
}
class PrinterPage extends StatefulWidget {
const PrinterPage({super.key});
@override
State<PrinterPage> createState() => _PrinterPageState();
}
class _PrinterPageState extends State<PrinterPage> {
final printer = EasyBluePrinter.instance;
List<BluetoothDevice> devices = [];
bool isConnected = false;
bool isLoading = false;
Future<void> scan() async {
setState(() => isLoading = true);
devices = await printer.getPairedDevices();
setState(() => isLoading = false);
}
Future<void> connect(BluetoothDevice device) async {
setState(() => isLoading = true);
isConnected = await printer.connectToDevice(device);
setState(() => isLoading = false);
}
Future<void> printReceipt() async {
await printer.printData(
data: 'My Store',
fontSize: FS.large,
textAlign: TA.center,
bold: true,
);
await printer.printData(
data: '------------------------',
fontSize: FS.normal,
textAlign: TA.center,
bold: false,
);
await printer.printData(
data: 'Item 1 R$ 10.00',
fontSize: FS.normal,
textAlign: TA.left,
bold: false,
);
await printer.printData(
data: 'Item 2 R$ 25.00',
fontSize: FS.normal,
textAlign: TA.left,
bold: false,
);
await printer.printData(
data: '------------------------',
fontSize: FS.normal,
textAlign: TA.center,
bold: false,
);
await printer.printData(
data: 'TOTAL R$ 35.00',
fontSize: FS.medium,
textAlign: TA.left,
bold: true,
);
await printer.printEmptyLine(callTimes: 5);
}
Future<void> disconnect() async {
await printer.disconnectFromDevice();
setState(() => isConnected = false);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Printer Example')),
body: Column(
children: [
// Scan button
Padding(
padding: const EdgeInsets.all(16),
child: ElevatedButton(
onPressed: isLoading ? null : scan,
child: isLoading
? const CircularProgressIndicator()
: const Text('Scan Devices'),
),
),
// Device list
Expanded(
child: ListView.builder(
itemCount: devices.length,
itemBuilder: (context, index) {
final device = devices[index];
return ListTile(
title: Text(device.name),
subtitle: Text(device.address),
onTap: () => connect(device),
);
},
),
),
// Print and disconnect buttons
if (isConnected) ...[
ElevatedButton(
onPressed: printReceipt,
child: const Text('Print Receipt'),
),
TextButton(
onPressed: disconnect,
child: const Text('Disconnect'),
),
const SizedBox(height: 16),
],
],
),
);
}
}
Donations #
If this package helped you, consider buying me a coffee!
PIX: 17ec92dc-89cf-4eb9-be90-8cab0fc2460c
Contributing #
Contributions are welcome! Feel free to open a PR or report issues on the repository.
License #
This project is distributed under the MIT license. See the LICENSE file for details.
Portugues #
Funcionalidades #
- Escanear dispositivos Bluetooth
- Conectar e desconectar de impressoras
- Imprimir texto com tamanho de fonte, alinhamento e negrito
- Imprimir imagens a partir de bytes
- Imprimir linhas em branco (alimentar papel)
- Verificar status da conexao
- Configurar o tamanho da bobina (58mm, 80mm ou customizado) para impressao correta de imagens
- Fila de impressao embutida — envios sequenciais e nao concorrentes, sem necessidade de delays manuais
- Funciona no Android e iOS
Plataformas Suportadas #
| Plataforma | Versao Minima |
|---|---|
| Android | SDK 24 (7.0) |
| iOS | 13.0 |
| Flutter | 3.44.0 |
| Dart | 3.12.0 |
No iOS o plugin fornece tanto um Swift Package (ios/easy_blue_printer/Package.swift) quanto o
podspec do CocoaPods, entao funciona nas duas integracoes sem configuracao extra.
No Android o plugin usa Built-in Kotlin: nao aplica mais o Kotlin Gradle Plugin, portanto nao
dispara mais o aviso de build plugins that apply Kotlin Gradle Plugin (KGP).
Instalacao #
Adicione no seu pubspec.yaml:
dependencies:
easy_blue_printer: ^latest_version
Depois execute:
flutter pub get
Configuracao por Plataforma #
Android #
Adicione estas permissoes no android/app/src/main/AndroidManifest.xml:
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
<application ...>
No Android 12+ o plugin solicita as permissoes automaticamente em tempo de execucao.
iOS #
Adicione estas chaves no ios/Runner/Info.plist:
<key>NSBluetoothAlwaysUsageDescription</key>
<string>Este app precisa do Bluetooth para conectar a impressoras</string>
<key>NSBluetoothPeripheralUsageDescription</key>
<string>Este app precisa do Bluetooth para conectar a impressoras</string>
Inicio Rapido #
import 'package:easy_blue_printer/easy_blue_printer.dart';
final printer = EasyBluePrinter.instance;
// 1. Escanear dispositivos
final devices = await printer.getPairedDevices();
// 2. Conectar a um dispositivo
final connected = await printer.connectToDevice(devices.first);
// 3. Configurar tamanho da bobina (chamar uma vez apos conectar)
await printer.configurePrinter(PaperConfig.roll80mm); // ou PaperConfig.roll58mm
// 4. Imprimir texto
await printer.printData(
data: 'Ola, Mundo!',
fontSize: FS.medium,
textAlign: TA.center,
bold: true,
);
// 5. Alimentar papel
await printer.printEmptyLine(callTimes: 5);
// 6. Desconectar
await printer.disconnectFromDevice();
Referencia da API #
EasyBluePrinter.instance #
Instancia singleton. Use para acessar todos os metodos.
getPairedDevices() #
Escaneia e retorna uma lista de dispositivos Bluetooth disponiveis.
Future<List<BluetoothDevice>> getPairedDevices()
Retorno: Lista de objetos BluetoothDevice com as propriedades name e address.
connectToDevice(device) #
Conecta a uma impressora Bluetooth.
Future<bool> connectToDevice(BluetoothDevice device)
| Parametro | Tipo | Descricao |
|---|---|---|
device |
BluetoothDevice |
Dispositivo retornado por getPairedDevices() |
Retorno: true se conectou com sucesso.
disconnectFromDevice() #
Desconecta da impressora atual.
Future<bool> disconnectFromDevice()
Retorno: true se desconectou com sucesso.
printData(...) #
Imprime texto formatado.
Future<bool> printData({
required String data,
required FS fontSize,
required TA textAlign,
required bool bold,
})
| Parametro | Tipo | Descricao |
|---|---|---|
data |
String |
Texto para imprimir |
fontSize |
FS |
Tamanho da fonte (ver Enums) |
textAlign |
TA |
Alinhamento (ver Enums) |
bold |
bool |
Ativar negrito |
Retorno: true se imprimiu com sucesso.
printEmptyLine(callTimes) #
Alimenta o papel imprimindo linhas em branco.
Future<void> printEmptyLine({required int callTimes})
| Parametro | Tipo | Descricao |
|---|---|---|
callTimes |
int |
Quantidade de linhas em branco |
printImage(bytes, textAlign) #
Imprime uma imagem na impressora termica.
Future<bool> printImage({
required Uint8List bytes,
required TA textAlign,
})
| Parametro | Tipo | Descricao |
|---|---|---|
bytes |
Uint8List |
Dados da imagem em bytes |
textAlign |
TA |
Alinhamento da imagem (ver Enums) |
Retorno: true se imprimiu com sucesso.
Exemplo — imprimir dos assets:
import 'package:flutter/services.dart';
final byteData = await rootBundle.load('assets/images/logo.png');
final bytes = byteData.buffer.asUint8List();
await printer.printImage(bytes: bytes, textAlign: TA.center);
configurePrinter(config) #
Configura o tamanho da bobina utilizado na impressao de imagens. Chame uma vez apos conectar na impressora.
Future<void> configurePrinter(PaperConfig config)
| Parametro | Tipo | Descricao |
|---|---|---|
config |
PaperConfig |
Configuracao da bobina |
Exemplo:
// Bobina 58mm (padrao)
await printer.configurePrinter(PaperConfig.roll58mm);
// Bobina 80mm
await printer.configurePrinter(PaperConfig.roll80mm);
// Largura customizada em pixels
await printer.configurePrinter(PaperConfig(widthPixels: 480));
Afeta apenas
printImage. A impressao de texto e controlada pelo firmware da impressora e nao precisa desta configuracao.
isConnected() #
Verifica se uma impressora esta conectada.
Future<bool> isConnected()
Retorno: true se estiver conectado.
commandDelay #
Delay configuravel aplicado entre comandos de impressao consecutivos. A fila interna ja serializa todos os comandos; este delay da tempo extra para a impressora processar cada comando antes do proximo chegar.
Duration commandDelay // padrao: Duration(milliseconds: 100)
Exemplo:
// Aumentar para impressoras mais lentas que ainda mostram caracteres invalidos
printer.commandDelay = const Duration(milliseconds: 150);
// Desativar para impressoras rapidas que nao precisam
printer.commandDelay = Duration.zero;
Aplicado apenas entre comandos enfileirados. Nao adiciona latencia apos o ultimo comando de um lote.
Enums #
FS — Tamanho da Fonte #
| Valor | Descricao |
|---|---|
FS.normal |
Tamanho normal |
FS.medium |
Tamanho medio |
FS.large |
Tamanho grande |
FS.huge |
Tamanho extra grande |
TA — Alinhamento do Texto #
| Valor | Descricao |
|---|---|
TA.left |
Alinhar a esquerda |
TA.center |
Centralizar |
TA.right |
Alinhar a direita |
PaperConfig — Tamanho da Bobina #
| Valor / Construtor | Largura | Descricao |
|---|---|---|
PaperConfig.roll58mm |
384 px | Bobina de 58mm (mais comum, padrao) |
PaperConfig.roll80mm |
576 px | Bobina de 80mm |
PaperConfig(widthPixels: n) |
custom | Qualquer largura customizada em pixels |
PrintDensity — Densidade de Impressao #
Opcional. Controla quanto a cabeca termica aquece a cada ponto (ESC 7). Mais calor escurece o
traco e melhora a leitura de texto pequeno e de codigos de barras, ao custo de imprimir um pouco
mais devagar e de gastar mais a cabeca.
| Valor | Aquecimento | Descricao |
|---|---|---|
| omitido (padrao) | — | Nao envia comando; mantem o valor de fabrica da impressora |
PrintDensity.normal |
80 | Padrao de fabrica da maioria das termicas |
PrintDensity.dark |
120 | Um passo mais escuro — resolve texto miudo apagado |
PrintDensity.darkest |
160 | Limite pratico antes de o traco comecar a borrar |
// Impressao mais escura numa bobina de 80mm
await printer.configurePrinter(
PaperConfig.roll80mm.copyWith(density: PrintDensity.dark),
);
Nem toda impressora implementa o
ESC 7. A maioria das que nao implementam simplesmente o ignora, mas ha modelos que imprimem os parametros como texto — por isso nada e enviado a menos que voce peca uma densidade.
Exemplo Completo #
import 'package:easy_blue_printer/easy_blue_printer.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(home: const PrinterPage());
}
}
class PrinterPage extends StatefulWidget {
const PrinterPage({super.key});
@override
State<PrinterPage> createState() => _PrinterPageState();
}
class _PrinterPageState extends State<PrinterPage> {
final printer = EasyBluePrinter.instance;
List<BluetoothDevice> devices = [];
bool isConnected = false;
bool isLoading = false;
Future<void> scan() async {
setState(() => isLoading = true);
devices = await printer.getPairedDevices();
setState(() => isLoading = false);
}
Future<void> connect(BluetoothDevice device) async {
setState(() => isLoading = true);
isConnected = await printer.connectToDevice(device);
setState(() => isLoading = false);
}
Future<void> printReceipt() async {
await printer.printData(
data: 'Minha Loja',
fontSize: FS.large,
textAlign: TA.center,
bold: true,
);
await printer.printData(
data: '------------------------',
fontSize: FS.normal,
textAlign: TA.center,
bold: false,
);
await printer.printData(
data: 'Item 1 R\$ 10,00',
fontSize: FS.normal,
textAlign: TA.left,
bold: false,
);
await printer.printData(
data: 'Item 2 R\$ 25,00',
fontSize: FS.normal,
textAlign: TA.left,
bold: false,
);
await printer.printData(
data: '------------------------',
fontSize: FS.normal,
textAlign: TA.center,
bold: false,
);
await printer.printData(
data: 'TOTAL R\$ 35,00',
fontSize: FS.medium,
textAlign: TA.left,
bold: true,
);
await printer.printEmptyLine(callTimes: 5);
}
Future<void> disconnect() async {
await printer.disconnectFromDevice();
setState(() => isConnected = false);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Exemplo Impressora')),
body: Column(
children: [
// Botao de escanear
Padding(
padding: const EdgeInsets.all(16),
child: ElevatedButton(
onPressed: isLoading ? null : scan,
child: isLoading
? const CircularProgressIndicator()
: const Text('Escanear Dispositivos'),
),
),
// Lista de dispositivos
Expanded(
child: ListView.builder(
itemCount: devices.length,
itemBuilder: (context, index) {
final device = devices[index];
return ListTile(
title: Text(device.name),
subtitle: Text(device.address),
onTap: () => connect(device),
);
},
),
),
// Botoes de imprimir e desconectar
if (isConnected) ...[
ElevatedButton(
onPressed: printReceipt,
child: const Text('Imprimir Recibo'),
),
TextButton(
onPressed: disconnect,
child: const Text('Desconectar'),
),
const SizedBox(height: 16),
],
],
),
);
}
}
Doacoes #
Se este pacote te ajudou, considere me pagar um cafe!
PIX: 17ec92dc-89cf-4eb9-be90-8cab0fc2460c
Contribuindo #
Contribuicoes sao bem-vindas! Sinta-se a vontade para abrir um PR ou reportar problemas no repositorio.
Licenca #
Este projeto e distribuido sob a licenca MIT. Veja o arquivo LICENSE para mais detalhes.