Como imprimir DANFEs e NFSe Nacional no Flutter usando um único package centralizado

Quem já precisou imprimir documentos fiscais em Flutter, principalmente em ambientes de PDV, POS, kiosks ou impressoras térmicas ESC/POS, sabe o quanto isso pode virar um pesadelo rapidamente.

Cada tipo de documento tem seu layout, cada município tem sua NFSe, cada impressora se comporta de um jeito… e quando você soma tudo isso, o código vira uma mistura difícil de manter.

Caso queiram ver um teste online e colocar seus xmls
https://danfe.brasizza.com

Pensando exatamente nesse cenário nasceu o package DANFE, que centraliza parse, normalização, renderização e impressão de documentos fiscais eletrônicos em Flutter, incluindo:

  • DANFE (NFC-e, SAT e NFe)
  • NFSe Nacional
  • Conversão para buffer ESC/POS
  • Renderização como Widget Flutter
  • Geração de Imagem
  • Possibilidade de layouts customizados

Tudo isso usando um único package, com uma API consistente.


Qual problema esse package resolve?

Antes de entrar no código, vale entender o problema real.

Normalmente, projetos que imprimem documentos fiscais sofrem com:

  • Código duplicado para cada tipo de documento
  • Diferenças entre SAT, NFC-e, NFe e NFSe
  • Layouts amarrados à impressora
  • Dificuldade de pré-visualizar o documento na tela
  • Impressões inconsistentes entre modelos de POS

O objetivo do package DANFE é resolver isso criando uma camada única de normalização, onde o XML vira um objeto padronizado e, a partir dele, você escolhe como quer renderizar ou imprimir.


O que exatamente o package faz?

De forma resumida, o fluxo funciona assim:

  1. Você fornece um XML
  2. O package identifica o tipo do documento
  3. Normaliza tudo em um modelo único
  4. A partir desse modelo, você pode:
    • Imprimir direto em ESC/POS
    • Gerar Widget Flutter
    • Gerar imagem
    • Criar layouts customizados

Funcionalidades principais

  • Parse automático de SAT, NFC-e e NFe
  • Suporte a NFSe Nacional (Beta)
  • Criação de buffer ESC/POS (List<int>)
  • Conversão para Widget Flutter
  • Conversão para imagem
  • Layouts customizados
  • Exemplo completo no projeto

Trabalhando com DANFE (NFC-e, SAT e NFe)

Parseando o XML

Tudo começa transformando o XML em um objeto Danfe.

import 'package:danfe/danfe.dart';

Danfe? danfe = DanfeParser.readFromString(xml);


O parser identifica automaticamente se o XML é SAT, NFC-e ou NFe e já normaliza os dados.

Gerando buffer ESC/POS para impressão

Aqui é onde o package começa a brilhar em ambientes de POS.

import 'package:danfe/danfe.dart';
import 'package:esc_pos_utils_plus/esc_pos_utils_plus.dart';

DanfePrinter danfePrinter = DanfePrinter(PaperSize.mm80);
List<int> dados = await danfePrinter.bufferDanfe(danfe);


Esse buffer já vem com um layout padrão pensado para impressoras térmicas.
Imprimindo em impressora de rede

final profile = await CapabilityProfile.load();

NetworkPrinter printer = NetworkPrinter(PaperSize.mm80, profile);
await printer.connect('192.168.5.29', port: 9100);
printer.rawBytes(dados);
printer.disconnect();


Simples, direto e reutilizável.

Visualizando o DANFE como Widget Flutter

Uma das grandes vantagens do package é não ficar preso à impressão.

Você pode transformar o DANFE em JSON normativo e renderizar direto na UI:

DanfePrinter danfePrinter = DanfePrinter(PaperSize.mm80);
String jsonDanfe = danfePrinter.normativeJsonDanfe(danfe);

ImageDanfe imageDanfe = ImageDanfe(
  jsonData: jsonDanfe,
  paperSize: DanfePaperSize.mm80,
);

Widget danfeWidget = await imageDanfe.toWidget(context);

Isso permite:

  • Preview antes de imprimir
  • Compartilhamento
  • Debug visual
  • Uso em Flutter Web


Convertendo DANFE em imagem

Uint8List imageBytes = await imageDanfe.toImage(context);

Perfeito para:

  • Salvar no dispositivo
  • Enviar para API
  • Mostrar preview em tela cheia
  • Imprimir como imagem

Imprimindo DANFE via imagem (ESC/POS)

Em alguns casos, imprimir como imagem gera resultados ainda mais consistentes entre impressoras.

List<Uint8List> imageParts = await imageDanfe.toEscPosPrinter(
  context,
  maxHeight: 2000,
  maxWidth: 576,
  margin: 0,
  fixedRatio: 1.0,
);


Depois é só enviar cada parte para a impressora usando esc_pos_utils_plus.

Criando layouts personalizados

Se o layout padrão não atende seu negócio, você pode criar o seu próprio:

final CustomPrinter custom = CustomPrinter(PaperSize.mm80);
List<int> dados = await custom.layoutCustom(danfe);

Isso é ideal para:

  • Branding próprio
  • Informações adicionais
  • Ajustes específicos de PDV

Trabalhando com NFSe Nacional

O package também suporta NFSe Nacional, seguindo o padrão unificado.

⚠️ Importante: apenas NFSe Nacional é suportada.
O XML é identificado pelo campo versaoAplicativo contendo a palavra “Nacional”.



Parseando NFSe Nacional

Nfse? nfse = NfseParser.readFromString(xmlNfse);


Verificando rapidamente se o XML é NFSe Nacional

Map<String, String>? info = NfseParser.extractBasicInfo(xmlNfse);

if (info != null) {
  print(info['tipo']);   // NFSe Nacional
  print(info['versao']);
  print(info['numero']);
}


Imprimindo NFSe Nacional

NfsePrinter nfsePrinter = NfsePrinter(PaperSize.mm80);
List<int> dados = await nfsePrinter.bufferNfse(nfse);


E a impressão segue exatamente o mesmo fluxo do DANFE.

NFSe como Widget ou Imagem

O processo é idêntico ao DANFE, reaproveitando a mesma infraestrutura:

String jsonNfse = nfsePrinter.normativeJsonNfse(nfse);

Por que centralizar tudo em um único package?

Em projetos reais de PDV, essa abordagem traz vantagens enormes:

  • Menos código duplicado
  • Menos bugs
  • Layout consistente
  • Facilidade de manutenção
  • Possibilidade de evoluir o layout sem quebrar impressão
  • Preview em tela antes de imprimir

É exatamente o tipo de solução que escala bem conforme o sistema cresce.