➙ Conteúdo completo, texto e vídeo, em: https://www.thiengo.com.br/leitor-de-codigos-no-android-com-barcode-scanner-api-zxing
Neste conjunto de slides vamos, passo a passo, ao estudo completo da biblioteca Barcode Scanner API para assim utilizar de maneira simples, mas robusta, o projeto ZXing, em aplicativos Android, na leitura de simbologias de códigos de barras.
➙ Para receber o conteúdo do blog em primeira mão, assine a lista de emails em: http://www.thiengo.com.br
Abraço.
▶ Treinamento oficial:
➙ Prototipagem Profissional de Aplicativos Android:
↳ https://www.udemy.com/android-prototipagem-profissional-de-aplicativos/?couponCode=BAR_CODE_LEITOR&persist_locale&locale=pt_BR
▶ Livros oficiais:
➙ Desenvolvedor Kotlin Android - Bibliotecas para o dia a dia:
↳ https://www.thiengo.com.br/livro-desenvolvedor-kotlin-android
➙ Receitas Para Desenvolvedores Android:
↳ https://www.thiengo.com.br/livro-receitas-para-desenvolvedores-android
➙ Refatorando Para Programas Limpos:
↳ https://www.thiengo.com.br/livro-refatorando-para-programas-limpos
▶ Redes:
➙ Udemy: https://www.udemy.com/user/vinicius-thiengo/?persist_locale&locale=pt_BR
➙ YouTube: https://www.youtube.com/user/thiengoCalopsita
➙ Facebook: https://www.facebook.com/thiengoCalopsita
➙ LinkedIn: https://www.linkedin.com/in/vin%C3%ADcius-thiengo-5179b180/
➙ GitHub: https://github.com/viniciusthiengo
➙ Twitter: https://twitter.com/thiengoCalops
➙ Google Plus: https://plus.google.com/+ThiengoCalopsita
▶ Blog App:
➙ https://play.google.com/store/apps/details?id=br.thiengocalopsita&hl=pt_BR
ViewModel Android, Como Utilizar Este Componente de Arquitetura
Barcode Scanner API - Leitor de códigos no Android com ZXing
1. Leitor de Códigos no
Android com Barcode
Scanner API - ZXing
thiengo.com.br
2. Proposta Barcode Scanner API
Em termos de "programação" temos dois famosos projetos
open source para que possamos criar rapidamente nossos
próprios aplicativos leitores de códigos:
- ZXing;
- ZBar.
O "porém" para uso de ambos os projetos é que a
implementação não é tão trivial como deveria ser, tendo em
vista que muitas populares bibliotecas Android precisam de
poucas linhas de código, como, por exemplo, a library
Android-State.
A biblioteca Barcode Scanner, que atende a partir do
Android 8 (Froyo), inicialmente desenvolvida por
Dushyanth, tem a proposta de fornecer a rápida integração
com qualquer um dos projetos, ZXing ou ZBar, e o fácil uso
destes, com uma interface pública simples e que atende às
principais funcionalidades para apps de leitura de código.
3. Por que a escolha do ZXing ao invés do ZBar?
Ambos os projetos são excelentes para a comunidade open
source. O ZBar tem uma proposta boa e uma documentação
completa sobre o seu funcionamento interno.
Porém, ao menos pela interface oferecida pelo Barcode Scanner,
quando em produção, mesmo prometendo a possibilidade de
leitura de exatos 16 tipos de simbologias de códigos, o ZBar
respondeu bem somente para a leitura de QR Codes.
O ZXing, mesmo tendo uma interface pública via Barcode Scanner
menos trivial do que a do ZBar, não falhou em nenhum dos códigos
testados, isso com as mesmas condições: aparelho e sistema
Android.
Devido a está discrepância em eficácia entre os dois projetos, é
prudente manter o estudo somente do ZXing via Barcode Scanner.
4. A seguir a tabela de simbologias de códigos de leitura possível quando utilizando o
projeto ZXing:
1D produto 1D industrial 2D
UPC-A CODE 39 QR Code
UPC-E CODE 93 Data Matrix
EAN-8 CODE 128 Aztec
EAN-13 CODABAR PDF417
ITF MaxiCode
RSS-14
RSS-Expanded
6. Instalação da API
No Gradle App Level, ou build.gradle (Module: app), coloque:
Lembre de utilizar implementation ao invés de compile, o compile está
depreciado no Gradle. Não esqueça também de sempre utilizar a última versão
estável da API, na época da construção deste conteúdo a última versão era a 1.9.8.
Ao final sincronize o projeto.
7. Resolvendo problemas de conflitos de versões de bibliotecas
Pode ser que você tenha problemas de incompatibilidade de versão das
bibliotecas já em uso em seu projeto com as referenciadas pela library
me.dm7.barcodescanner:zxing, neste caso, uma maneira de resolver é
excluindo as bibliotecas antigas e compilando o projeto com as mais atuais.
Na época da construção deste conteúdo o Android Studio apontou que a referência
a com.android.support:support-v4 em me.dm7.barcodescanner:zxing era de
versão inferior à já referenciada por outras bibliotecas do projeto.
Neste caso optei como solução a "exclusão do módulo antigo" no momento da
compilação, ou seja, o módulo support-v4 da biblioteca
me.dm7.barcodescanner:zxing:
8. Depois da configuração de exclusão de API é necessário realizar novos testes no
aplicativo, isso para garantir que não haverá problemas de crash.
Caso você tenha problemas, tente o inverso, excluindo a versão mais atual. Não
deixe de também avaliar outras opções de remoção de APIs em conflito.
Lembrando… como o conflito foi com a referência com.android.support:support-
v4, temos que:
- group = com.android.support;
- module = support-v4.
9. Definindo permissões
No AndroidManifest, adicione as duas <uses-permission> em destaque:
Como a permissão de câmera é uma dangerous permission, é necessário ter em
código a solicitação desta permissão em tempo de execução.
Mais sobre como realizar este tipo de solicitação, no link a seguir: Sistema de
Permissões em Tempo de Execução, Android M.
10. Como uma breve solução, podemos utilizar a biblioteca EasyPermissions, que é
muito bem aceita pela comunidade de desenvolvedores Android, é simples de
utilizar e atende a todas as versões do Android em mercado.
No Gradle App Level, ou build.gradle (Module: app), adicione a seguinte
referência e sincronize o projeto:
Já na primeira atividade, ou fragmento, que utiliza a câmera para leitura de código,
coloque os algoritmos de solicitação e recebimento (ou não recebimento) de
permissão.
Algoritmos junto a Interface EasyPermissions.PermissionCallbacks:
11.
12. Note que o código anterior é apenas um exemplo, simples, para conseguirmos a
solicitação de permissão de câmera em tempo de execução, logo, não deixe de ler
por completo o artigo sobre permissões indicado anteriormente.
Uma ressalva sobre a permissão de acesso ao LED de flash do device: coloque
ela se parte de seu domínio do problema exigir também o trabalho com flash, caso
contrário, pode descartar essa permissão.
13. Permitindo a instalação somente em devices com câmera
É prudente permitir que seu aplicativo apareça na Play Store somente para
devices que têm câmera disponível. Para isso adicione ao AndroidManifest.xml a
tag <uses-feature>:
14. Definição de ZXingScannerView
No arquivo XML de layout da atividade ou fragmento que terá a responsabilidade
de abrir o leitor de código, coloque:
Note que os valores dos atributos são definidos por ti, acima temos apenas um
exemplo.
Há a possibilidade de também definir o ZXingScannerView via código de
programação, como a seguir:
15. Definindo o manipulador de resultados de leitura
Com a Interface ZXingScannerView.ResultHandler vamos conseguir ter o
método que permitirá a obtenção do resultado da leitura de código:
16. No código anterior o z_xing_scanner é uma referência a View
ZXingScannerView. Como estamos trabalhando com Kotlin e o plugin kotlin-
android-extensions, não há necessidade de findViewById().
O método setResultHandler() requer uma instância de
ZXingScannerView.ResultHandler como argumento. Segundo a documentação,
o lugar ideal de invocação deste método é no onResume() do fragmento ou
atividade em uso.
Se o método resumeCameraPreview() não for invocado posteriormente à leitura
de algum código, a tela de leitura fica travada. resumeCameraPreview() também
espera uma instância de ZXingScannerView.ResultHandler como argumento.
Lembrando que todo o código apresentado é passível de ser utilizado também em
fragmentos.
17. Iniciando a câmera para leitura de código
Ainda em onResume() invoque o método startCamera():
18. A partir do ponto de invocação do método startCamera() a atenção deve ser
redobrada, pois aqui se iniciam os principais problemas caso você não saiba a
regra de negócio para invocação deste método:
- Invoque o startCamera() somente se os recursos de câmera estiverem todos
disponíveis, ou seja:
- Na abertura da entidade que contém o startCamera(), onde nenhum recurso
de câmera ainda foi alocado;
- Depois do stopCamera() completo. Este é crítico, pois a liberação de
recursos não é síncrona. No próximo slide estudaremos melhor o
"stopCamera() completo”.
Caso não respeite os itens acima, acredite, ou a câmera nem mesmo vai funcionar,
ou caso funcione: trabalhará de modo inconsistente.
19. Parando a câmera e liberando recursos
Exatamente no método onPause() da atividade ou fragmento em uso, invoque o
algoritmo de stop e liberação de recursos de câmera:
O trecho de código a partir de CameraUtils.getCameraInstance() é necessário
para devices com versões mais antigas do Android, anteriores a API 22, segundo
meus testes. Caso o release() não seja invocado e haja alguma estratégia de
abertura de câmera em uma outra atividade, por exemplo, a câmera não
funcionará nesta nova abertura e travará a anterior.
20. Em caso de reconstrução de atividade, sem o release() a câmera também deixará
de funcionar.
Ok, mas este código de release() trabalha também para versões do Android que
não necessitam dele?
Sim, não terá algum efeito negativo nestes aparelhos.
Muito cuidado com o uso de CameraUtils.getCameraInstance(), isso, pois a
invocação deste método, mesmo quando utilizando o argumento de ID de câmera,
termina o funcionamento da câmera em tela. Logo, somente utilize
CameraUtils.getCameraInstance() depois do stopCamera() ou quando não
houver a necessidade de trabalho com câmera em tela.
Isso é um bug?
Provavelmente, pois a interface pública, nativa a Barcode Scanner API, para
verificação de recurso de flash depende de CameraUtils.getCameraInstance().
Assim acaba que não podemos utilizar o isFlashSupported() devido a este
entrave.
21. Em todos os testes onde necessitei de utilizar algum recurso de câmera, a câmera
em tela parava de responder. Logo, podemos assumir que esta é uma limitação da
API nativa do Android, Camera API. Pois os projetos Barcode Scanner e ZXing
ainda utilizam a Camera API ao invés da Camera2 API.
De qualquer forma não deixa de ser um bug em Barcode Scanner, pois nem
mesmo na documentação tem algo sobre está limitação. Caso não possa
contornar algum problema, informe na doc sobre a limitação.
E a verificação de null, if( camera != null ), é necessária?
Sim. Pois, por exemplo, se o usuário entra em uma atividade que tem o uso da
Barcode Scanner API, porém tendo em mente que ele já veio de outra atividade
que também fazia uso desta API... e assumindo que na nova abertura ele
rapidamente volte a atividade anterior.
Este "rapidamente" pode ser o suficiente para que a câmera não tenha ainda sido
alocada em tela, ou seja, todos os recursos estão sendo liberados da primeira
atividade. Desta forma o código CameraUtils.getCameraInstance() retorna null.
Resumo: caso não tenha a verificação, uma exceção pode ser gerada.
22. Trabalho com luz de flash
Caso você queira oferecer está funcionalidade aos usuários de seu aplicativo Android,
o algoritmo é simples. Primeiro a definição da permissão no AndroidManifest:
Depois o código de verificação de existência de luz de flash no device:
23. Agora o algoritmo que contém a alternância de status da luz de flash, um exemplo:
Note que desta vez o context não é uma instância de
ZXingScannerView.ResultHandler e sim uma atividade, facilmente acessível
também via fragmento.
O código de verificação de recurso de flash é essencial, caso contrário excessões
serão geradas em devices que não têm o flash, e acredite: alguns não têm.
Ok, mas nós temos um recurso de verificação de flash direto na API Barcode
Scanner, certo?
Sim, temos, o CameraUtils.isFlashSupported(). Mas como informado em slides
anteriores, ele acaba não tendo valor algum, pois necessita do objeto câmera
como argumento e sabemos que se acessarmos este objeto a câmera para de
funcionar.
24. Permitindo mudança de orientação de tela
É comum que você queira permitir que o usuário mude a orientação da tela caso,
por exemplo, o leitor de código ocupe toda a extensão dela.
Porém, como informado em tópicos anteriores: há um sério problema com a
liberação de recursos de câmera. Esta liberação é assíncrona, ou seja, caso haja a
invocação do startCamera(), logo na reconstrução de atividade, antes da total
liberação de recursos de câmera utilizados na antiga instância da atividade, neste
cenário a câmera para de funcionar.
A melhor solução então é utilizar para está atividade o ConfigChanges:
Assim ela não será reconstruída e não haverá a possiblidade de conflito de
chamadas ao startCamera().
25. AutoFocus
Por padrão o AutoFocus é true. A vantagem de ter o AutoFocus ativo é que a
câmera é utilizada em sua maior capacidade para conseguir ler o código em teste:
A desvantagem é que caso o método resumeCameraPreview() seja invocado
logo depois de uma leitura e o código lido esteja ainda em tela, neste cenário
várias leituras continuam ocorrendo. Mas isso não tira a qualidade da biblioteca,
nem mesmo se compara ao problema de colocar setAutoFocus(false).
Problema?
Sim. A câmera deixa de ser utilizada com maior desempenho para leitura de
código... e em devices mais antigos, com câmeras menos robustas, segundo meus
testes, somente QR Code é passível de ser lido.
26. Verificação de câmera em funcionamento
Caso seja uma necessidade de sua lógica de negócio saber quando a câmera já
está funcionando na interface do usuário, utilize o método isShow() para isso:
27. Configuração para devices HUAWEI
Para o correto funcionamento da API Barcode Scanner em devices HUAWEI, a
documentação solicita que o seguinte código seja definido antes do
startCamera():
Porém a invocação a setAspectTolerance(0.5F) faz com que em devices de
outras marcas a leitura de código fique dificultada se o ZXingScannerView não
estiver ocupando toda a tela do device.
Ou seja, para utilizar o método setAspectTolerance() sem problemas em
aparelhos diversos, coloque também um algoritmo de verificação de marca de
device:
28. Outras configurações
Caso queira mudar as cores de borda, utilize o método setBorderColor() como a
seguir:
Para mudar a cor do laser, ou linha central, utilize o método setLaserColor() como
a seguir:
29. Para mudar a cor de máscara, fade, utilize o método setMaskColor() como a
seguir:
30. Caso queira por algum motivo rotacionar a caixa de leitura da câmera, utilize
rotation como a seguir:
Somente trabalhe com rotation se houver real necessidade, pois segundo meus
testes a eficiência de leitura de código cai consideravelmente se o valor de
rotation não for o padrão: 0.0F.
31. Se por algum motivo você necessite definir as simbologias de códigos que podem
ser lidas, utilize o método setFormats():
O código acima informa a API que somente QR Codes e Data Matrix é que podem
ser interpretados, os outros formatos devem ser ignorados.
32. Pontos negativos
- A API Camera1 ainda é utilizada sem o suporte da API Camera2. Mesmo assim
funcionou sem problemas em um device Android API 26;
- A documentação tanto da biblioteca Barcode Scanner quanto do projeto ZXing
não são completos em relação a codificação no Android. Muitas das regras de
negócio foram descobertas durante os testes;
- A versão ZBar ainda não está boa para ser liberada e infelizmente, ao menos na
referência a API Barcode Scanner no Android-Arsenal, é exatamente o código
do ZBar que é utilizado;
- Não há uma maneira trivial de trabalharmos o zoom e nem mesmo planos para
adicionar esta funcionalidade;
- Não é possível redimensionar, com uma interface simples, o box de leitura de
código ou: CameraPreview. O redimensionamento é somente automático,
respeitando as dimensões disponíveis para a câmera;
33. - Não há uma interface pública segura para realizarmos a conexão com a câmera
somente depois de recursos liberados;
- Se é preciso criar um objeto Result de ZXing, temos de utilizar um construtor
mínimo que ainda exige argumentos que não serão utilizados, deveria ter
também um construtor esperando somente os dados: conteúdo e formato de
código de barras;
- A Barcode Scanner deveria ter uma mesma interface pública para trabalho com
o ZXing ou com o ZBar, assim teríamos de escolher, via constante, por exemplo,
com qual trabalhar;
- Está faltando uma interface simples para corrigir o problema de orientação de
câmera, pois em alguns devices, alguns poucos, a câmera fica invertida em
relação a posição do device.
34. Pontos positivos
- Interface pública muito simples de ser utilizada em relação as interfaces
públicas dos projetos ZXing e ZBar;
- Permite que de maneira trivial tenhamos um leitor de código em apenas parte
da tela, com o restante contendo outros conteúdos complementares;
- Os métodos de customização dos componentes visuais da API facilitam que
todo o projeto fique com o mesmo aspecto de design;
- Quando utilizando o projeto ZXing para leitura de códigos, tudo é bem rápido
independente do formato da simbologia de código.
35. Conclusão
Apesar dos vários problemas citados, junto a eles também foram expostas
soluções que atendem bem a qualquer domínio de problema que necessite de
leitura de simbologias de códigos de barras.
De todas as limitações citadas, a que realmente preocupa é o ainda uso somente
da Camera API, é preciso que a Camera2 API seja também trabalhada. Logo, em
seu projeto, não deixe de realizar todos os testes possíveis com a interface
pública da API Barcode Scanner.
De qualquer forma, principalmente para aqueles que têm conhecimento de causa
com o domínio de leitura de simbologias de códigos, a Barcode Scanner API
adianta em muito a inclusão desta funcionalidade ao aplicativo e pelo o que vi na
comunidade: é a mais bem aceita.
36. Fontes
Conteúdo completo, em texto e em vídeo, no link a seguir:
- https://www.thiengo.com.br/leitor-de-codigos-no-android-com-barcode-scanner-
api-zxing
Fontes:
- https://github.com/dm77/barcodescanner
- https://github.com/zxing/zxing
- http://zbar.sourceforge.net/
- https://github.com/dm77/barcodescanner/issues/193
- https://github.com/zxing/zxing/issues/527
- https://github.com/dm77/barcodescanner/issues/278
- https://developer.android.com/guide/topics/manifest/uses-feature-element.html?
hl=pt-br
- https://stackoverflow.com/a/19599365/2578331
- https://stackoverflow.com/a/27836910/2578331
- https://stackoverflow.com/a/10803992/2578331
37. Para estudo
- Treinamento oficial:
- Prototipagem Profissional de Aplicativos Android.
- Meus livros:
- Receitas Para Desenvolvedores Android;
- Refatorando Para Programas Limpos.
- Redes:
- Udemy;
- YouTube;
- Facebook;
- LinkedIn;
- GitHub;
- Twitter;
- Google Plus.
- Blog App.
38. Leitor de Códigos no Android com
Barcode Scanner API - ZXing
thiengo.com.br
Vinícius Thiengo
thiengocalopsita@gmail.com