Utilizando Zxing para ler código de barras.

19 Flares Twitter 2 Facebook 8 Google+ 4 LinkedIn 5 Filament.io 19 Flares ×

Update: Este post ficou obsoleto. Atualmente para efetuar a leitura de código de barras deve ser utilizada a solução nativa BarcodeDetector.  Veja o vídeo oficial de divulgação:

 

Quando é preciso fazer leitura de códigos de barras em um projetos não é preciso quebrar muito a cabeça, basta integrar ao projeto Android um leitor de códigos de barras, a lib mais popular par isso é a ZXing. Para quem não sabe este é um projeto de uma lib para leitura de código de barras e é livre, qualquer um que quiser pode utilizar.  A grande sacada dele é que você pode incluí-lo diretamente em seu projeto fazendo com que o usuário não precise se preocupar em instalar um leitor de código de barras para que seu aplicativo funcione. Ele ainda possui um app nativo do projeto que serve exclusivamente para leitura de códigos, chamado Barcode Scanner.

Quando procurei informações sobre como fazer a integração achei pouco material que fosse claro, inclusive no site oficial do ZXing do projeto. Após algumas buscas encontrei esse tutorial do ZXing que explica de forma simples e clara como fazer esta integração. Fiz tudo conforme está indicado lá mas não consegui fazer a integração funcionar de forma alguma. Sendo assim voltei ao google e achei outro projeto chamado android-zxinglib. Ele é uma implementação simplificada do ZXing. Esse sim funcionou.

O bom dele é que é bem autoexplicativo. No site existem dois arquivos para download. Um é a biblioteca do ZXing, já modificada pelo autor, e outro é um projeto de exemplo onde é possível visualizar como fazer a integração da forma mais simples possível. Basta copiar tudo pro seu projeto e sair usando. Basicamente é preciso criar um xml com o layout da leitura, colocar a lib do zxing no projeto e fazer a chamada do leitor.

O xml pode ser customizado como você preferir. Eu copiei do projeto de exemplo do ZXingLib e só alterei os textos.

As libs do zxing (core.jar e zxingjar-1.1.jar) eu coloquei dentro da pasta lib do meu projeto.

Depois adicionei elas no Java Build Path do projeto:

Para que possamos fazer a chamada desta library é preciso criarmos o layout que será executado sobre ela. Esse passo é necessário pois não é possível utilizar os resources da lib. Portanto abaixo segue o código do layout que vou utilizar:

<?xml version="1.0" encoding="UTF-8"?>
<FrameLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
	android:layout_width="fill_parent" 
	android:layout_height="fill_parent">

	<SurfaceView 
	    android:id="@+id_capture/preview_view"
		android:layout_width="fill_parent" 
		android:layout_height="fill_parent"
		android:layout_centerInParent="true">
	</SurfaceView>

	<jim.h.common.android.zxinglib.view.ViewfinderView
		android:id="@+id_capture/viewfinder_view" 
		android:layout_width="fill_parent"
		android:layout_height="fill_parent" 
		android:background="#00000000">
	</jim.h.common.android.zxinglib.view.ViewfinderView>

	<TextView 
	    android:id="@+id_capture/status_view" 
	    android:layout_width="wrap_content"
		android:layout_height="wrap_content" 
		android:layout_gravity="bottom|center_horizontal"
		android:background="#00000000" 
		android:text="Posicione o código de barras no local indicado"
		android:textColor="#ffffffff" 
		android:textSize="14sp">
	</TextView>
</FrameLayout>

Depois é preciso fazer a chamada do leitor:

IntentIntegrator.initiateScan(	ListarProdutos.this,
	                	R.layout.capture,
	                	R.id_capture.viewfinder_view,
	                	R.id_capture.preview_view,
	                	false);

E pegar o resultado no retorno do Intent:

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        switch (requestCode) {
            case IntentIntegrator.REQUEST_CODE:
                IntentResult scanResult = IntentIntegrator.parseActivityResult(requestCode, resultCode, data);
                final String result = scanResult.getContents();
                if ((result != null) && (scanResult.getFormatName().toString().contentEquals("EAN_13"))) {
                    handler.post(new Runnable() {
                        public void run() {
                            Intent it = new Intent(getBaseContext(), EditarProduto.class);
            				it.putExtra("cod_barras", result);
            				startActivity(it);
            	        }
                    });
                } else {
                	Toast.makeText(getBaseContext(), "Código inválido ou inexistente.", 5).show();
                }
                break;
            default:
        }
    }

Antes de executar é necessário modificar o seu Android Manifest para que tudo funcione corretamente:

<uses-permission android:name="android.permission.CAMERA"/>
<activity
    android:name="jim.h.common.android.zxinglib.CaptureActivity"
    android:screenOrientation="landscape"
    android:configChanges="orientation|keyboardHidden"
    android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
    android:windowSoftInputMode="stateAlwaysHidden">
</activity>

Note que no retorno da leitura da câmera eu fiz uma validação verificando se o código é um EAN13 ou não. Para mim isso era importante mas você pode necessitar de alguma outra validação.