Todo app corporativo que sai da fase inicial encontra cedo ou tarde o mesmo requisito: anexar evidencias. Pode ser foto de visita, comprovante, PDF, ordem assinada, imagem de equipamento, documento fiscal ou arquivo de suporte. A partir desse momento, o aplicativo deixa de lidar apenas com campos de texto e passa a enfrentar um pacote inteiro de desafios: permissao de camera e galeria, tamanho de arquivo, compressao, fila local, upload em rede ruim, API que precisa aceitar anexos e suporte que depois vai perguntar onde aquele arquivo se perdeu.
No React Native com Expo, boa parte da coleta tecnica fica acessivel por bibliotecas oficiais. Isso ajuda muito, mas nao elimina as decisoes de arquitetura. O maior erro e tratar upload como um detalhe de interface. Em app corporativo, anexos participam do fluxo operacional. Eles precisam chegar ao servidor certo, ligados ao registro certo, com status claro para o usuario e comportamento previsivel quando a internet oscila.
Este guia organiza um caminho pratico para lidar com fotos, documentos e upload sem transformar anexo em mais uma fonte de retrabalho.
1. Comece pelo evento de negocio, nao pelo botao de camera
A primeira pergunta nao e qual biblioteca abre a camera. E por que esse anexo existe.
Perguntas uteis:
- o arquivo comprova o que dentro do processo?
- o upload precisa ser imediato ou pode entrar em fila?
- o usuario pode enviar mais de um anexo?
- foto e documento seguem a mesma regra?
- o servidor aceita substituicao, complementaridade ou apenas um arquivo?
- o arquivo precisa ser lido depois em auditoria ou apenas no momento da operacao?
Quando o fluxo nasce sem esse desenho, a equipe implementa camera e galeria, mas so depois descobre que faltava vincular o anexo ao item certo, armazenar status, suportar reenvio ou diferenciar comprovante obrigatorio de evidencias opcionais.
2. Foto e documento pedem fluxos parecidos, mas nao identicos
A documentacao da Expo mostra duas trilhas oficiais bem claras: `expo-image-picker` para imagens e videos da biblioteca ou camera, e `expo-document-picker` para documentos vindos dos provedores disponiveis no dispositivo. Isso ja indica uma separacao importante.
Fotos costumam exigir:
- camera ou galeria;
- compressao e dimensao razoavel;
- preview rapido;
- orientacao para luz, foco e contexto.
Documentos costumam exigir:
- tipo MIME permitido;
- nome de arquivo compreensivel;
- tamanho maximo;
- leitura ou reenvio posterior.
O erro comum e criar um unico campo "anexo" e fingir que tudo e igual. Em app corporativo, imagem de visita, PDF e arquivo tecnico raramente seguem a mesma regra de negocio.
3. Permissao precisa fazer sentido no contexto
A pagina do ImagePicker mostra que a biblioteca pode configurar mensagens de `photosPermission`, `cameraPermission` e `microphonePermission` no app config, e que permissoes que dependem de build devem ser decididas antes. Isso e um lembrete importante: permissao nao e detalhe de ultima hora.
Boas praticas:
- pedir camera apenas perto do fluxo que realmente precisa de foto;
- explicar por que a galeria sera usada;
- bloquear permissao que o app nao precisa, como microfone se ele nao faz sentido;
- testar o comportamento quando a pessoa negar acesso;
- nao misturar upload de documento com pedido de camera sem necessidade.
Se a permissao aparecer sem contexto, o usuario desconfia. E a loja tambem. O artigo checklist de publicacao Android e iOS ajuda a conectar permissao com qualidade de release.
4. Copiar para cache e uma decisao tecnica, nao so conveniencia
A documentacao do DocumentPicker explica que, ao usar `expo-document-picker` junto com `expo-file-system`, nem sempre o arquivo pode ser lido imediatamente depois da selecao. Para permitir leitura imediata, o `copyToCacheDirectory` deve estar como `true`. A mesma documentacao tambem alerta que isso pode impactar performance em arquivos grandes.
Essa observacao resolve muita dor real. Em termos praticos:
- se o app precisa ler, validar ou subir logo em seguida, copiar para cache ajuda;
- se o arquivo pode ser muito grande e nao sera lido imediatamente, talvez voce queira evitar copia desnecessaria;
- o fluxo precisa saber se esta trabalhando com URI temporaria, cache local ou copia persistida.
Sem essa clareza, o time pega um arquivo no picker, tenta enviar direto e descobre tarde demais que outra API do app nao conseguiu ler o conteudo.
5. Imagem boa para operacao nao e imagem no tamanho maximo
O ImagePicker retorna informacoes do asset como `fileName`, `fileSize`, `height`, `width` e `uri`. Isso ja basta para uma primeira validacao de negocio. Em seguida, a documentacao do ImageManipulator mostra que `manipulateAsync` pode salvar a imagem com `compress` entre `0.0` e `1.0`.
Na pratica, isso significa que um app corporativo nao deveria subir toda foto no tamanho bruto sem criterio. Vale decidir:
- qual resolucao minima preserva a evidencia necessaria;
- qual tamanho maximo por arquivo o backend aceita;
- se a compressao acontece antes do upload;
- se a imagem original precisa ser mantida em algum caso regulatorio.
Exagerar na compressao prejudica leitura. Nao comprimir nada aumenta tempo de envio, consumo de dados e falha em rede ruim. O ponto certo depende do processo, nao apenas da biblioteca.
6. Base64 raramente e a melhor escolha para anexos grandes
Quando o upload entra na conversa, algumas equipes convertem tudo para base64 por ser facil de inspecionar. O problema e que isso aumenta payload e memoria. A documentacao do FileSystem mostra caminhos mais diretos: enviar arquivos como `body` de `fetch`, usar `FormData`, ou criar upload task com progresso.
Regra pratica para app corporativo:
- prefira fluxo de arquivo real quando o backend aceita multipart ou corpo binario;
- use base64 com muito criterio em casos pequenos e bem justificados;
- registre nome, tipo e tamanho antes do envio;
- nao assuma que a rede aguenta anexos grandes como se fossem texto.
Isso aproxima o app da realidade operacional. Arquivo precisa ser tratado como arquivo, nao como string inflada escondida dentro do JSON.
7. Upload precisa de status visivel para o usuario
A documentacao do FileSystem registra que `createUploadTask` permite controle de upload com progresso. Mesmo quando a implementacao escolher outro caminho, a ideia continua valida: o usuario precisa enxergar o estado do envio.
Estados comuns:
- selecionado;
- validado localmente;
- aguardando envio;
- enviando;
- sincronizado;
- falhou e precisa reenviar.
App corporativo nao deveria mostrar so um spinner mudo. Se o anexo e parte da operacao, o usuario precisa saber se ele ja foi, se esta pendente ou se travou por falta de rede.
8. Fila local faz diferenca quando o upload depende da rua, nao do escritorio
Se a pessoa trabalha em campo, a internet vai oscilar no pior momento. Por isso, anexos precisam conversar com a estrategia de offline e fila local. Em vez de tentar enviar na hora e desistir silenciosamente, o app pode registrar o anexo como pendente.
Campos uteis na fila:
- identificador local;
- URI local atual;
- tipo MIME e tamanho;
- item de negocio ao qual o anexo pertence;
- numero de tentativas;
- ultimo erro;
- status do upload.
Isso conversa diretamente com cache, fila e sincronizacao com API. Um anexo importante nao deveria desaparecer porque a resposta falhou no elevador ou na estrada.
9. A API precisa tratar upload como contrato, nao como improviso
Do lado do servidor, vale responder perguntas tecnicas cedo:
- o endpoint aceita multipart form data ou upload binario?
- qual tamanho maximo por arquivo?
- quais tipos MIME sao validos?
- o item principal precisa existir antes do anexo?
- o upload e idempotente ou pode duplicar evidencias?
- o backend devolve URL final, status e identificador do anexo?
Se a API nao e clara, o app vira laboratorio de tentativa e erro. E upload mal definido gera dois custos: frustra o usuario e bagunca auditoria depois.
10. Android pode matar a Activity, e isso afeta coleta de imagem
A documentacao do ImagePicker faz um alerta importante: no Android, o sistema pode destruir a `MainActivity` depois que o picker termina. Nesses casos, o app pode recuperar o dado com `getPendingResultAsync`.
Esse detalhe vale ouro para app de campo. Sem ele, a equipe testa em aparelhos bons e acha que tudo funciona. Em aparelho mais pressionado pelo sistema, a foto pode ser tirada, mas o app perde o resultado ao voltar.
Se o fluxo de evidencia e importante, esse caso precisa entrar na validacao. O problema nao aparece todo dia, mas quando aparece, derruba confianca do usuario no momento em que ele jurava que ja tinha anexado tudo.
11. Limpeza de cache e retencao local tambem fazem parte do desenho
Depois que o upload termina, o app precisa decidir o que fazer com o arquivo local. Guardar tudo para sempre aumenta ocupacao e risco. Apagar cedo demais pode atrapalhar reenvio ou auditoria local.
Perguntas uteis:
- o arquivo local deve ser apagado depois da confirmacao do backend?
- algum fluxo exige manter copia por tempo curto?
- o usuario consegue reenviar sem selecionar tudo de novo?
- logout limpa anexos pendentes do usuario anterior?
Esse tipo de decisao faz parte da fronteira entre mobile, seguranca local e operacao.
12. Checklist para fotos e anexos com menos susto
- Definir o papel do anexo no processo de negocio.
- Separar foto, video e documento quando as regras forem diferentes.
- Configurar permissoes no app com contexto humano.
- Decidir quando copiar o arquivo para cache local.
- Validar nome, tipo, tamanho e vinculacao do anexo.
- Comprimir imagem com criterio antes do envio quando fizer sentido.
- Escolher upload binario ou multipart em vez de inflar tudo em base64.
- Mostrar progresso e status visivel de envio.
- Persistir fila local quando o anexo depende de rede instavel.
- Testar Android com `getPendingResultAsync` em cenarios mais hostis.
- Definir regra de limpeza ou retencao local depois do sucesso.
- Alinhar endpoint, limites e retorno do backend.
13. Erros comuns
- subir foto original enorme sem compressao nem limite;
- usar um unico fluxo para PDF e imagem como se fossem iguais;
- pedir camera sem necessidade ou sem explicacao;
- guardar anexo pendente sem estado claro;
- perder resultado do ImagePicker no Android por nao tratar pending result;
- depender de base64 para anexos grandes;
- nao validar tipo MIME e tamanho no backend;
- fingir que upload falhou so porque a resposta demorou sem olhar fila e retry.
14. Quando vale revisar a arquitetura de upload
Se o app esta sofrendo com anexos perdidos, comprovante duplicado, foto lenta demais, API confusa ou suporte sem rastreabilidade, talvez o problema nao seja um botao. Seja o desenho inteiro do fluxo de upload. Nessa hora, um diagnostico tecnico pode ajudar a alinhar mobile, API, fila, seguranca local e experiencia do usuario antes que a operacao fique dependente de improviso.
Fotos e anexos costumam parecer detalhe no backlog. Mas, em app corporativo, eles sao evidencia. Quando permissao, compressao, fila e API trabalham juntas, o anexo deixa de ser um ponto cego e vira parte confiavel do processo.
Referencias editoriais: Expo ImagePicker, Expo DocumentPicker, Expo ImageManipulator e Expo FileSystem.
Termos tecnicos desta leitura
Alguns conceitos aparecem com frequencia neste tema. Abrir o glossario ajuda a comparar definicoes, exemplos e leituras relacionadas sem sair do contexto do artigo.