Alura > Cursos de Mobile > Cursos de Flutter > Conteúdos de Flutter > Primeiras aulas do curso Flutter: utilizando bluetooth para conexão com impressoras POS

Flutter: utilizando bluetooth para conexão com impressoras POS

Acesso ao bluetooth - Apresentação

Olá, meu nome é Matheus Alberto, sou instrutor aqui na Alura.

Audiodescrição: Matheus se identifica como um homem branco. Possui cabelos castanhos escuros e a barba bem feita. Utiliza uma camiseta preta, óculos de grau com armação preta e brincos pretos nas orelhas. Ao fundo, uma parece quadriculada em tons de roxo, com três barras verticais de luz branca à direita.

Conhecendo o projeto

Já pensou em desenvolver um projeto que se comunica com impressoras de POS (pontos de acesso)? Quando fazemos um pedido em um restaurante, imprimimos uma receita ou pegamos um recibo, a impressão é feita por uma impressora de POS. Foi isso que um cliente, o Panucci Ristorante, nos solicitou.

Precisamos desenvolver um sistema que se comunica com uma dessas impressoras de POS, para imprimir comandos do restaurante para a cozinha e também para pagamento da clientela, utilizando, por exemplo, um QR Code para enviar um código PIX.

O que aprenderemos?

Aprenderemos a trabalhar com permissões, pois precisamos solicitar permissão do dispositivo para utilizar o Bluetooth. Assim que tivermos a permissão, podemos nos comunicar e estabelecer a primeira conexão com a impressora.

Temos um menu com uma seção onde podemos nos comunicar com dispositivos pareados — no caso, a nossa impressora. Ao selecionar o dispositivo a ser pareado, a aplicação fornecerá um feedback visual tanto no dispositivo quanto na própria impressora, indicando que a comunicação foi estabelecida.

Também exploraremos como configurar essa impressora para diferentes tipos de papel e tamanhos de fonte e testar se realmente conseguimos imprimir algo com nossa impressora.

Após realizar todos os testes e estabelecer a comunicação, podemos imprimir nossa comanda. Faremos um pedido simples com as opções de comida da aplicação Panucci para observar o processo em ação. Assim que clicarmos em "Enviar para a cozinha", a comanda será impressa.

Além disso, aprenderemos a trabalhar com Bluetooth dentro do nosso aplicativo, abordando técnicas de arquitetura, organização de código e boas práticas, além de utilizar plugins desenvolvidos pela comunidade para facilitar o processo de comunicação.

Pré-requisitos

Para acompanhar este curso, é essencial ter conhecimentos sólidos de Flutter, incluindo gerenciamento de dados e injeção de dependências.

Mergulhe conosco! Nos vemos no próximo vídeo

Acesso ao bluetooth - Conhecendo o projeto, tarefa e pacotes

Nosso cliente, o Panucci Ristorante, solicitou o desenvolvimento de um sistema que se conecte à impressora POS para imprimir uma comanda. Essa comanda servirá tanto para a cozinha quanto para a clientela após o pagamento do pedido.

Compreendendo o sistema existente

Já temos um aplicativo disponível que possui toda a parte visual desenvolvida, além de algumas regras de negócios. Nossa função será fazer com que o aplicativo se conecte à impressora e imprima a comanda.

Vamos analisar o aplicativo. Ele possui uma tela inicial que solicita acesso ao dispositivo via Bluetooth:

Tela de permissão para acesso ao Bluetooth da aplicação Panucci Ristorante. O fundo é branco. No topo, o texto em preto diz 'Permissões'. Abaixo, há um ícone vermelho de um símbolo de Bluetooth. Em seguida, o texto em preto diz 'Precisamos de acesso ao seu Bluetooth'. O subtítulo em preto informa, 'Para fazer a impressão, a aplicação precisa de autorização do seu dispositivo para acessar o Bluetooth.' Mais abaixo, há um botão vermelho com o texto branco 'Autorizar Bluetooth' e um botão com um texto vermelho que diz 'Agora não'.

Após clicar em "Autorizar Bluetooth", haverá o redirecionamento para a página principal do aplicativo, na qual podemos adicionar produtos:

Tela de menu digital do aplicativo Panucci Ristorante. No topo, há um botão de retorno e o título 'Cardápio' à esquerda, e o botão com um ícone de impressora à direita. Abaixo, encontra-se uma barra de busca com o texto 'Buscar um item' e uma lupa. A seção 'Mais comprados' exibe itens como 'Chicken Salad' por R$ 58,90, 'Chicken Tender' por R$ 49,90, e 'Chicken Pizza' por R$ 35,50, cada um com botões de adição e subtração de quantidade. Mais abaixo, a seção 'Para o almoço' mostra 'Cold Noodles' por R$ 37,50, 'Hamburger Ink' por R$ 48,50, e 'Pamonha' por R$ 10,00, também com botões para ajuste de quantidade. A última seção é 'Para dividir', exibindo 'Lasagna' por R$ 55,00, 'Shrimp 'n rice' por R$ 68,50, e 'Rice 'n Beans' por R$ 35,00, todos com ícones para aumentar ou diminuir a quantidade.

Ao adicionar pelo menos um item, um botão vermelho aparece na parte inferior do aplicativo para visualizar o pedido. Ao clicar nesse botão, temos a tela abaixo, com um resumo do pedido realizado, o total da compra e um botão para enviar para a cozinha:

Tela de pedido do aplicativo Pannuci Ristorante. No topo, há um botão de retorno e o título 'Pedido' em texto grande. Abaixo, uma lista de itens pedidos com imagens pequenas à esquerda, cada uma com o nome e o preço ao lado. Mais abaixo, a seção 'Pagamento' exibe o cartão 'VISA Classic' com números parcialmente ocultos e uma seta para a direita. Na seção 'Confirmar', o texto mostra o total do pedido. Na parte inferior da tela, há um botão vermelho grande com o texto 'Enviar para cozinha'.

É nesse processo, ao clicar no botão de enviar para a cozinha, que o pedido será impresso na impressora POS.

Configurando a conexão com a impressora

Clicaremos no botão de retorno para voltar à página principal. Nesta, clicaremos no botão de impressora no canto superior direito que nos redirecionará para outra página, onde podemos escolher o dispositivo ao qual desejamos nos conectar:

Tela de dispositivos emparelhados do aplicativo Pannuci Ristorante. Há o título 'Dispositivos Pareados' na parte superior, ao lado de um botão de retorno à esquerda e um ícone de engrenagem à direita. Abaixo, o texto 'Bluetooth' aparece em destaque.

O restaurante pode ter mais de uma impressora, dependendo do seu tamanho, pois uma única impressora pode não ser suficiente para imprimir os pedidos de várias pessoas. Assim, podemos escolher a impressora à qual queremos nos conectar. Ao clicar em um dispositivo, a conexãos será estabelecida.

No canto superior direito, clicaremos no botão de engrenagem que nos levará à tela de configuração da impressão, na qual podemos ajustar o tamanho do papel, o tamanho da fonte, salvar as configurações e imprimir uma página de teste para verificar se a impressora está funcionando corretamente:

Tela de configurações para impressão do aplicativo Pannuci Ristorante. No topo, há o texto 'Configurações' e uma seta de retorno à esquerda. Mais abaixo, um ícone vermelho de impressora. O texto 'Configuração de impressão' está centralizado abaixo do ícone. A página instrui a seleção de configurações básicas de impressão com os textos 'Tamanho do papel' seguido de um menu suspenso mostrando '58mm', e 'Tamanho da fonte' com outro menu suspenso exibindo '1'. Na parte inferior, há um botão vermelho arredondado com o texto 'Salvar configuração', em branco, e abaixo, um botão branco contornado com o texto 'Imprimir teste', em vermelho.

Escolhendo os plugins necessários

Esse é o processo para realizar a impressão da comanda. Para fazer isso, o primeiro passo é identificar os recursos que podemos utilizar para facilitar essa comunicação.

Utilizaremos dois plugins:

O print_bluetooth_thermal necessita do esc_pos_utils_plus para funcionar.

Vamos acessá-los no navegador.

Vamos instalar esses dois plugins na versão 1.1.5 para o print_bluetooth_thermal e na versão 2.0.4 para o esc_pos_utils_plus.

Instalando os pacotes no projeto

Acessando o editor de código, abriremos o terminal com "Ctrl = '" e executaremos os comandos abaixo separadamente para instalar os pacotes necessários:

flutter pub add print_bluetooth_thermal
flutter pub add esc_pos_utils_plus

Com os plugins instalados, o próximo passo é consultar a documentação.

No navegador, acessaremos a documentação do plugin print_bluetooth_thermal. Um dos exemplos fornecidos é verificar se o Bluetooth está ativado. Este é um teste importante, pois permite acessar diretamente o Bluetooth do dispositivo e confirmar se ele está realmente ligado.

Copiaremos a linha de código fornecida:

final bool result = await PrintBluetoothThermal.bluetoothEnabled;

É importante notar que a função é assíncrona devido ao uso de await.

Implementando e testando a funcionalidade

Com o trecho de código copiado, retornaremos ao editor de código. Acessando o explorador de arquivos lateral, abriremos o caminho de pastas "lib > screens" e acessaremos o arquivo checkout que possui a página de Checkout, onde está localizado o botão de enviar para a cozinha.

Por volta do final do código, temos o child: CheckoutButton(). Entre seus parênteses, alteraremos a função onTap para assíncrona e colaremos o trecho de código entre suas chaves.

checkout.dart:

child: CheckoutButton(
    onTap: () async {
        final bool result = await PrintBluetoothThermal.bluetoothEnabled;
    },
),

Em seguida, importaremos o pacote PrintBluetoothThermal com a ajuda do editor.

import 'package:print_bluetooth_thermal/print_bluetooth_thermal.dart';

Por precaução, reiniciaremos o aplicativo para garantir que os pacotes estão atualizados. Após a instalação, abriremos o emulador e clicaremos em "Autorizar Bluetooth". Na tela principal, selecionaremos um item do cardápio para que o botão de enviar para a cozinha apareça. No entanto, ao clicar nesse botão, nada aconteceu.

Identificando e corrigindo o problema de permissão

No editor, abriremos o terminal, na aba "DEBUG CONSOLE". Inicialmente, parece que nada ocorreu, mas ao pressionar fisicamente o botão no dispositivo, uma mensagem de aviso apareceu:

Warning: permission bluetooth granted is false, check in settings that the permission of nearby devices is activated.

Isso indica que não temos permissão para usar o Bluetooth. Mesmo sem passar pela página de liberação do Bluetooth, o erro persiste, indicando a necessidade de resolver o problema de permissão para utilizar o plugin.

Acesso ao bluetooth - Gerenciando permissões de bluetooth com o permission handler

Quando tentamos utilizar o plugin para verificar se nosso dispositivo está com o Bluetooth ligado, ao clicar no botão de "Enviar para a Cozinha", o debug indica que não temos permissão para utilizar o Bluetooth.

Para resolver esse problema de permissão, usaremos o Permission Handler, uma biblioteca do Flutter cuja função é lidar com permissões do dispositivo.

Instalando o Permission Handler

Vamos abrir essa biblioteca no navegador.

Página do permission_handler

O pacote Permission Handler que utilizaremos é o 11.3.1. No editor de código, abriremos o terminal e rodaremos:

flutter pub add permission_handler

A instalação da permissão será concluída.

Por que usar o Permission Handler?

Alguns pacotes que não trabalham com ferramentas nativas do dispositivo possuem funcionalidades para pedir permissão. Escolhemos usar o Permission Handler em vez de uma função de permissão do próprio plugin, pois o Permission Handler tem como única função lidar com permissões.

Se o Android ou iOS atualizarem de forma que as permissões precisem ser implementadas de maneira diferente, os pacotes que usamos, por serem geridos pela comunidade, pode não ser atualizados a tempo, causando problemas nos aplicativos. O Permission Handler nos ajuda a evitar esse erro, criando uma dependência para lidar com permissões e isolando as variáveis de permissão.

Configurando permissões no AndroidManifest.xml

Temos uma lista de permissões que precisamos usar, pois o Permission Handler permite várias permissões no Android. Precisaremos modificar o arquivo AndroidManifest.xml, localizado em "android > app > src > main". Nesse arquivo, adicionaremos duas permissões.

Além do Permission Handler, precisamos inserir manualmente as permissões no XML, conforme os padrões da Google para publicação de aplicativos.

Abaixo da tag application, pularemos duas linhas. No caso do vídeo, há um comentário abaixo dessa tag, mas podemos trabalhar antes ou depois dele. O importante é que esteja entre o fechamento da tag application e a abertura da tag queries.

As permissões que precisamos são <uses-permission android:name="android.permission.BLUETOOTH_SCAN" />, e outra permissão BLUETOOTH_CONNECT. Podemos copiar a primeira linha e substituir "SCAN" por "CONNECT".

AndroidManifest.xml:

<uses-permission android:name="android.permission.BLUETOOTH_SCAN" /> 
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" /> 

Pedindo permissão à pessoa usuária

Podemos pedir permissão à pessoa usuária na página inicial do aplicativo onde solicitamos a permissão do Bluetooth, em vez de pedir na página do Checkout. Pelo explorador lateral, acessaremos o caminho "lib > screens" e abriremos o arquivo permissions_screen.dart.

Em seu interior, temos um botão chamado CustomPrimaryButton, que utiliza Navigator.push() para navegar até a tela Home. Antes de navegar, vamos pedir permissão.

O Permission Handler também trabalha com funções assíncronas, então precisamos transformar a função OnTap em assíncrona. Entre as chaves dessa função, vamos solicitar a permissão com await Permission.

permissions_screen.dart:

CustomPrimaryButton(
    onTap: () async {
        await Permission
        Navigator.push(context, MaterialPageRoute(builder: (context) => Home()));
        }
    },
    text: "Autorizar Bluetooth",
),

Ao digitar await Permission, importaremos esse elemento do pacote de permission_handler.

import 'package:permission_handler/permission_handler.dart';

Digitando um ponto após Permission, o editor exibirá as opções disponíveis de request: bluetooth, bluetoothAdvertise, bluetoothConnect e bluetoothScan. Vamos utilizar Connect e Scan.

Começaremos pelo Scan, que foi o primeiro que colocamos, seguido de outro await Permission para o bluetoothConnect. Finalizaremos os dois comandos com .request().

onTap: () async {
    await Permission.bluetoothScan.request();
    await Permission.bluetoothConnect.request();
    Navigator.push(context, MaterialPageRoute(builder: (context) => Home()));
    }
},

Lidando com permissões negadas

Precisamos considerar o que acontece se a permissão for negada. Abaixo das solicitações de permissão, implementaremos uma condição para que, se as permissões não forem concedidas, não redirecionemos a pessoa usuária para outra página.

Assim, faremos um if com await Permission.bluetoothScan.isGranted e utilizamos dois e comerciais (&&) para a condição "e". Repetiremos o processo para Connect com await Permission.bluetoothConnect.isGranted.

Se ambas as permissões forem aceitas, navegaremos para a página Home. Para isso, moveremos o Navigator.push() para o interior das chaves dessa condição. Caso contrário, não fazemos nada, pois a pessoa usuária negou a permissão.

onTap: () async {
    await Permission.bluetoothScan.request();
    await Permission.bluetoothConnect.request();
    if (await Permission.bluetoothScan.isGranted && await Permission.bluetoothConnect.isGranted) {
        Navigator.push(context,
            MaterialPageRoute(builder: (context) => Home()));
    }
},

Falta imprimir o resultado. Acessando o arquivo da página de checkout, buscaremos o botão CheckoutButton.

No interior do botão, entre as chaves do onTap e abaixo do result, imprimiremos essa variável result.

checkout.dart:

child: CheckoutButton(
    onTap: () async {
        final bool result = await PrintBluetoothThermal.bluetoothEnabled;
        print(result);
    },
),

Garantindo a instalação correta

Após salvar, como instalamos um novo pacote e alteramos o Android Manifest, é uma boa prática parar o aplicativo, desinstalá-lo do dispositivo e reinstalá-lo. Isso garante que não haverá resíduos de permissões e que os pacotes estarão atualizados.

Testando a funcionalidade

Depois de reinstalar o aplicativo no dispositivo, voltaremos a abri-lo, Na tela Home, ao clicar em "Autorizar Bluetooth", um menu do Android é exibido na parte inferior da tela, solicitando permissão para usar o Bluetooth. Inicialmente, negaremos a permissão clicando em "Não permitir", e não haverá redirecionamento, conforme esperado. Ao clicar em "Autorizar Bluetooth" novamente e em "Permitir", tudo funcionará corretamente e acessaremos o menu principal.

Acessando o debug console do editor, limparemos as informações para facilitar a visualização. Voltando à aplicação, prepararemos um pedido para testar, selecionando alguns itens do cardápio.

Ao clicar em "Enviar para cozinha", verificaremos se o Bluetooth está ligado. Expandindo a barra de status do dispositivo, o ícone de Bluetooth indica que está ativado. Voltando ao debug console, verificaremos que o resultado é true, confirmando que o Bluetooth está ligado.

true

Sobre o curso Flutter: utilizando bluetooth para conexão com impressoras POS

O curso Flutter: utilizando bluetooth para conexão com impressoras POS possui 134 minutos de vídeos, em um total de 48 atividades. Gostou? Conheça nossos outros cursos de Flutter em Mobile, ou leia nossos artigos de Mobile.

Matricule-se e comece a estudar com a gente hoje! Conheça outros tópicos abordados durante o curso:

Aprenda Flutter acessando integralmente esse e outros cursos, comece hoje!

Conheça os Planos para Empresas