📚 Módulo 12: Mobile - Integração com Câmera (Leitor QRCode Pix) e Compilação EAS Cloud Build
Neste módulo final de encerramento da TecLoja 03, daremos o toque profissional e nativo definitivo ao nosso aplicativo móvel.
Implementaremos o fluxo de checkout e faturamento móvel integrando a Câmera do Dispositivo para leitura e decodificação de códigos QR de pagamento Pix. Por fim, utilizaremos os serviços em nuvem do Expo (EAS Build) para compilar o binário nativo final (.apk / .aab) de forma automática, eliminando a dependência de termos o Android Studio local instalado.
🗺️ 1. Fluxo de Checkout Pix Nativo e Leitura de Câmera
Abaixo, descrevemos a interação sequencial entre a câmera física do aparelho, a decodificação da string Pix e o encerramento do pedido no NestJS:
sequenceDiagram
participant U as Usuário (App)
participant C as Expo Camera Component
participant P as Pix Decoder (Scanner)
participant N as API NestJS (Backend)
U->>C: Clica em "Pagar com QRCode"
C->>U: Exibe tela de captura de câmera
U->>C: Aponta a câmera para o QR Code do Pix
C->>P: Captura frames de vídeo em tempo real
P-->>C: QR Code detectado e decodificado
C->>N: Enviar confirmação de pagamento (/api/pedidos/faturar)
N-->>U: Exibe "Pedido Realizado com Sucesso!"
📸 2. Leitor de QRCode Pix com expo-camera
Para capturar códigos QR em tempo real, utilizaremos o módulo de câmera oficial do ecossistema Expo.
Instalação
npx expo install expo-camera
Configuração de Permissões Nativa
Ao contrário do Android puro, o Expo gerencia as permissões no arquivo de configuração do app app.json. Abra app.json e adicione o plugin de câmera:
{
"expo": {
"name": "TecLoja 03 Mobile",
"slug": "tecloja-03-mobile",
"plugins": [
[
"expo-camera",
{
"cameraPermission": "Permitir acesso à câmera para ler códigos QR de pagamento do Pix."
}
]
]
}
}
Implementação da Tela de Pagamento (app/pagamento.tsx)
Crie o arquivo de tela de pagamento móvel utilizando os novos recursos:
import React, { useState, useEffect } from 'react';
import { StyleSheet, Text, View, Button, TouchableOpacity } from 'react-native';
import { Camera, CameraView } from 'expo-camera';
import { router } from 'expo-router';
export default function PagamentoScreen() {
const [temPermissao, setTemPermissao] = useState<boolean | null>(null);
const [escanado, setEscanado] = useState(false);
useEffect(() => {
(async () => {
const { status } = await Camera.requestCameraPermissionsAsync();
setTemPermissao(status === 'granted');
})();
}, []);
const handleBarCodeScanned = ({ type, data }: { type: string, data: string }) => {
setEscanado(true);
// Simulação didática de validação de código Pix da TecLoja
if (data.startsWith('000201')) {
alert(`Pagamento Pix processado com sucesso!\nDados: ${data.substring(0, 30)}...`);
router.replace('/(tabs)');
} else {
alert('Código QR inválido. Certifique-se de apontar para um Pix válido.');
setEscanado(false);
}
};
if (temPermissao === null) {
return <View style={styles.container}><Text style={styles.texto}>Solicitando permissão de câmera...</Text></View>;
}
if (temPermissao === false) {
return <View style={styles.container}><Text style={styles.texto}>Acesso à câmera foi negado.</Text></View>;
}
return (
<View style={styles.container}>
<Text style={styles.instrucoes}>Aponte a câmera para o QR Code de pagamento</Text>
<CameraView
onBarcodeScanned={escanado ? undefined : handleBarCodeScanned}
barcodeScannerSettings={{
barcodeTypes: ['qr'],
}}
style={StyleSheet.absoluteFillObject}
/>
{escanado && (
<TouchableOpacity style={styles.botaoReiniciar} onPress={() => setEscanado(false)}>
<Text style={styles.botaoTexto}>Escanear Novamente</Text>
</TouchableOpacity>
)}
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
flexDirection: 'column',
justifyContent: 'center',
backgroundColor: '#000',
},
texto: {
color: '#fff',
textAlign: 'center',
fontSize: 18,
},
instrucoes: {
color: '#fff',
textAlign: 'center',
fontSize: 16,
position: 'absolute',
top: 40,
width: '100%',
zIndex: 10,
backgroundColor: 'rgba(15, 23, 42, 0.8)',
paddingVertical: 12,
},
botaoReiniciar: {
position: 'absolute',
bottom: 40,
alignSelf: 'center',
backgroundColor: '#38bdf8',
paddingVertical: 12,
paddingHorizontal: 24,
borderRadius: 8,
zIndex: 10,
},
botaoTexto: {
color: '#0f172a',
fontWeight: 'bold',
}
});
🏗️ 3. Compilação Automatizada na Nuvem via EAS Build
Uma das maiores dores no desenvolvimento móvel tradicional é a necessidade de possuir um computador macOS potente para compilar binários iOS ou configurar o pesado ambiente do Android Studio localmente. O EAS (Expo Application Services) resolve isso realizando as compilações em servidores dedicados na nuvem do Expo.
Passo a Passo para Gerar a Build na Nuvem:
- Instalar a CLI Global do EAS:
No console global da sua máquina, instale a ferramenta de nuvem:
npm install -g eas-cli - Autenticar ou Criar Conta no Expo:
Crie uma conta gratuita em expo.dev e autentique-se no console local:
eas login - Configurar o Projeto para Builds:
Inicialize as configurações do EAS no projeto móvel. O comando lerá as propriedades locais e criará um arquivo
eas.json:eas build:configure - Ajustar o
eas.jsonpara Gerar APK de Testes: Por padrão, compilações Android de release geram o formato.aab(Android App Bundle, aceito apenas pela Play Store). Para testes locais, altere o perfilpreviewno arquivoeas.jsonpara produzir um arquivo.apkinstalável:{ "cli": { "version": ">= 9.0.0" }, "build": { "development": { "developmentClient": true, "distribution": "internal" }, "preview": { "distribution": "internal", "android": { "buildType": "apk" } }, "production": {} } } - Disparar a Build na Nuvem:
Execute o comando abaixo para iniciar o empacotamento em fila na nuvem:
eas build --platform android --profile preview - A CLI compactará o código JS e o enviará para os servidores do Expo. O console exibirá um link de rastreamento onde você poderá acompanhar o andamento em tempo real.
- Ao final da build, um QR Code será exibido diretamente no seu terminal. Basta escaneá-lo com seu celular para baixar e instalar o APK compilado nativo de sua TecLoja 03 instantaneamente!
✅ Pré-Requisitos deste Módulo
Antes de compilar a versão final móvel, confirme se:
- A API NestJS está estável e conectada ao banco PostgreSQL Neon em produção na Render.
- Você testou o fluxo de carrinho e persistência segura JWT no emulador (Módulo 11).
🤔 Por que fizemos assim?
- Por que usar EAS Build na nuvem em vez do build local? Compilar localmente exige instalar gigabytes de pacotes do Android SDK, Gradle, Command Line Tools e configurar variáveis complexas que dependem do sistema operacional host (Windows, Mac, Linux). Delegar o build para os servidores do Expo garante um ambiente limpo e isolado (Docker nativo do Expo) rodando sob hardware robusto, poupando recursos da máquina do estudante.
- Por que validar o padrão ‘000201’ no Pix? A string padrão do Pix EMV (padrão de pagamento do Banco Central do Brasil) sempre começa com os caracteres
000201. Validar essa assinatura impede que o aplicativo trave caso a câmera escaneie acidentalmente códigos de barras de boletos ou links de sites genéricos durante a simulação pedagógica.
🔍 Checkpoint
- Validação de Câmera: Inicie a tela de pagamento e confirme se o pop-up nativo solicitando acesso à câmera é disparado. Aponte para um gerador de Pix online e confirme se a decodificação ocorre em tempo real.
- Build Concluído: Acesse seu dashboard no site
expo.deve valide se a build do projeto consta como concluída (status “Success”) e possui o APK disponível para download.
⚠️ Erros Comuns
| Erro | Causa | Solução |
|---|---|---|
Camera permission denied |
O usuário negou o acesso ou os metadados do plugin de câmera não foram inseridos no app.json. |
Insira o bloco de plugins da câmera no app.json e limpe os dados do aplicativo no menu de configurações do Android. |
| O leitor de código escaneia o Pix mas não dispara nenhuma ação | A string do Pix gerada não inicia com o cabeçalho padrão EMV ou a função de callback está com o estado de travamento de scan travado em true. | Garanta que o código do scanner verifique corretamente a assinatura 000201 e resete a variável reativa escanado em caso de erro. |
| Fila de build no EAS muito demorada | Contas gratuitas do Expo compartilham uma fila de espera comunitária que pode demorar em horários de pico. | Planeje a build final com antecedência ou utilize o comando de build local npx expo run:android caso possua o Android Studio completo e potente instalado na máquina local. |