DesarrolloLibre

Desarrollo Web, Android, juegos y mucho más

Categorias
¡Actualizado el 03-08-2017!

En esta entrada veremos cómo crear un lector de códigos QR en Android; para hacerte a la idea, actualmente existen varios lectores QR en Android que los puedes encontrar en la Google Play; por nombrar algunos:

Crear un lector QR personalizado (creado por nosotros mismos en Android Studio) es bastante sencillo con Android y solo debemos incluir una librería externa la cual corresponde a com.google.android.gms:play-services-vision, pero antes de esto veamos qué es, cómo funciona un código QR y cómo podemos emplearlo en nuestras aplicaciones Android y webs:

¿Qué es un código QR?

Es un sistema que permite almacenar información en una especie de código de barras de última generación.
Un código QR es un tipo de código de barra pero en dos dimensiones en el cual se codifica información en un cuadro como el siguiente:
Código qr

Los códigos QR son realmente útiles para administrar inventarios, compartir datos e información de una manera fácil y muy profesional; los códigos QR son actualmente un elemento fundamental en cualquier aplicación de pequeña o gran envergadura debido a su versatilidad al momento de usarlos.

¿Para qué sirve un Código QR?

Como se comentó anteriormente, los códigos QR son ampliamente empleados debido a su versatilidad y gran utilidad; se emplean en todo tipo de productos como alimentarios hasta llegar a dispositivos, automóviles, revistas y otros tantos de tipos de ámbitos publicidad, marketing, etc...

...o como nuestro caso de interés como parte de un proceso en una aplicación Android...

...en donde podemos procesar medicinas e indicar al cliente si la medicina es de utilidad para su persona teniendo su perfil previamente cargado y sin necesidad de que el cliente suministre información o datos algunos de manera manual.

¿Cómo genero un código QR?

En Internet encontrarás una cantidad inmensa de formas para generar códigos QR; inclusive podemos crear códigos QR con librerías PHP, Java, etc; y existen webs que se encargan de generar códigos QR como la siguiente Genere su codigo QR gratis.

¿Cómo descifrar un código QR?

Con la ayuda de un móvil podemos recuperar esta información tan solo con apuntar la cámara hacia el código QR y esa es la idea y lo que haremos en la siguiente sección de esta entrada en donde nos dedicaremos a detallar a como crear un lector QR con Android.

Desarrollando nuestro propio lector de códigos QR en Android

Finalmente llegamos al área de interés en cuál es crear nuestro lector de códigos QR en Android; primero debemos agregar la dependencia necesaria en nuestro build.gradle.

Agregando la dependencia en el archivo build.gradle en Android Studio

Abrimos nuestro archivo build.gradle y agregamos la siguiente dependencia:

compile 'com.google.android.gms:play-services:11.0.4'

La anterior dependencia nos da acceso no solo a la API de vision si no a toda la plataforma que nos ofrece la Google Play como en nuestro caso de interés es solomenteleer un código QR, podemos emplear la siguiente dependencia en nuestro build.gradle:

compile 'com.google.android.gms:play-services-vision:11.0.4'

Debes tener presente que las versiones cambian de un día a otro; puedes encontrar la última versión en la documentación oficial en el siguiente enlace:

Set Up Google Play Services

Configurando el resto de la aplicación

Con nuestra dependencia ya configurada ahora podemos ir a nuestra actividad y/o fragment y crear los objetos, eventos y configuraciones necesarias para tener nuestro propio lector QR; pero primero debemos de configurar el layout del a actividad o fragment:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="16dp">

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:background="@color/colorSecondary"
        android:layout_gravity="center_horizontal"
        android:padding="8dp">

        <SurfaceView
            android:id="@+id/camera_view"
            android:layout_width="640px"
            android:layout_height="480px"
            android:layout_alignParentLeft="true"
            android:layout_centerVertical="true" />
    </LinearLayout>
</LinearLayout>

Y en nuestra actividad o fragment debemos crear un objeto de tipo BarcodeDetector esta clase permite reconocer códigos de barra y códigos QR -el cual es nuestro caso de interés- a través de la cámara del dispositivo y devolver un objeto de tipo SparseArray con el dato decodificado del QR analizado:

        // creo el detector qr
        barcodeDetector =
                new BarcodeDetector.Builder(getContext())
                        .setBarcodeFormats(Barcode.QR_CODE)
                        .build();

        // creo la camara fuente
        cameraSource = new CameraSource
                .Builder(getContext(), barcodeDetector)
                .setRequestedPreviewSize(640, 480)
                .build();
El objeto CameraSource permite obtener frames de la cámara del dispositivo y posteriormente analizarlo.

Especificamos el objeto SurfaceView de nuestro layout; este objeto se encarga de espejar o reflejar lo que estamos viendo por la cámara del dispositivo en nuestra superficie de nuestro layout:

cameraView = (SurfaceView) v.findViewById(R.id.camera_view);

Ahora especificamos los listener o escuchadores que permiten controlar el ciclo de vida de la cámara:

        // listener de ciclo de vida de la camara
        cameraView.getHolder().addCallback(new SurfaceHolder.Callback() {
            @Override
            public void surfaceCreated(SurfaceHolder holder) {

                // verifico si el usuario dio los permisos para la camara
                if (ContextCompat.checkSelfPermission(getContext(), android.Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED) {
                    try {
                        cameraSource.start(cameraView.getHolder());
                    } catch (IOException ie) {
                        Log.e("CAMERA SOURCE", ie.getMessage());
                    }
                } else {
                    Toast.makeText(getContext(), getResources().getString(R.string.error_camara), Toast.LENGTH_SHORT).show();
                }
            }

            @Override
            public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
            }

            @Override
            public void surfaceDestroyed(SurfaceHolder holder) {
                cameraSource.stop();
            }
        });
Un punto importante del código anterior es iniciar la cámara una vez que nuestra superficie sea dibujada.

Por último se prepara el evento que retornará el resultado provisto por la detección y procesamiento del QR; cuando existe una respuesta barcodes.size() nos devolverá un valor mayor a cero:

 // preparo el detector de QR
        barcodeDetector.setProcessor(new Detector.Processor<Barcode>() {
            @Override
            public void release() {
            }


            @Override
            public void receiveDetections(Detector.Detections<Barcode> detections) {
                final SparseArray<Barcode> barcodes = detections.getDetectedItems();

                if (barcodes.size() != 0) {
barcodes.valueAt(0).displayValue.toString();
                 // hacer algo
            }

barcodeDetector.release();
        });

Con el barcodes.valueAt(0).displayValue.toString(); obtenemos el dato devuelto por el QR que puede ser un texto, entero o una URL dependiendo cómo configuremos nuestro código QR.

Los permisos en Android 6 y superior

A partir de Android 6 Google creó un nuevo esquemas de permisos los cuales son solicitados al usuarios al momento de requerir emplear alguna función de dicho(s) permiso(s)...

...por lo tanto no basta con solo incluir la dependencia en nuestro AndroidManifest, también debemos solicitar el permiso propiamente dicho desde el código java de nuestra aplicación Android.

Entonces, al momento de construir nuestra superficie colocamos el siguiente código:

// listener de ciclo de vida de la camara
cameraView.getHolder().addCallback(new SurfaceHolder.Callback() {
   @Override
   public void surfaceCreated(SurfaceHolder holder) {

       // verifico si el usuario dio los permisos para la camara
       if (ActivityCompat.checkSelfPermission(QRActiviy.this, Manifest.permission.CAMERA)
               != PackageManager.PERMISSION_GRANTED) {

           if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
               // verificamos la version de Android que sea al menos la M para mostrar
               // el dialog de la solicitud de la camara
               if (shouldShowRequestPermissionRationale(
                       Manifest.permission.CAMERA)) ;
               requestPermissions(new String[]{Manifest.permission.CAMERA},
                       MY_PERMISSIONS_REQUEST_CAMERA);
           }
           return;
       } else {
           try {
               cameraSource.start(cameraView.getHolder());
           } catch (IOException ie) {
               Log.e("CAMERA SOURCE", ie.getMessage());
           }
       }
   }

   @Override
   public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
   }

   @Override
   public void surfaceDestroyed(SurfaceHolder holder) {
       cameraSource.stop();
   }
});

El código es relativamente sencillo, verificamos si el permiso fue concedido con checkSelfPermission y con shouldShowRequestPermissionRationale mostramos el dialog para solicitar el permiso.

Finalmente el código queda de la siguiente manera:


public void initQR() {

   // creo el detector qr
   barcodeDetector =
           new BarcodeDetector.Builder(this)
                   .setBarcodeFormats(Barcode.ALL_FORMATS)
                   .build();

   // creo la camara
   cameraSource = new CameraSource
           .Builder(this, barcodeDetector)
           .setRequestedPreviewSize(1600, 1024)
           .setAutoFocusEnabled(true) //you should add this feature
           .build();

   // listener de ciclo de vida de la camara
   cameraView.getHolder().addCallback(new SurfaceHolder.Callback() {
       @Override
       public void surfaceCreated(SurfaceHolder holder) {

           // verifico si el usuario dio los permisos para la camara
           if (ActivityCompat.checkSelfPermission(QRActiviy.this, Manifest.permission.CAMERA)
                   != PackageManager.PERMISSION_GRANTED) {

               if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                   // verificamos la version de ANdroid que sea al menos la M para mostrar
                   // el dialog de la solicitud de la camara
                   if (shouldShowRequestPermissionRationale(
                           Manifest.permission.CAMERA)) ;
                   requestPermissions(new String[]{Manifest.permission.CAMERA},
                           MY_PERMISSIONS_REQUEST_CAMERA);
               }
               return;
           } else {
               try {
                   cameraSource.start(cameraView.getHolder());
               } catch (IOException ie) {
                   Log.e("CAMERA SOURCE", ie.getMessage());
               }
           }
       }

       @Override
       public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
       }

       @Override
       public void surfaceDestroyed(SurfaceHolder holder) {
           cameraSource.stop();
       }
   });

   // preparo el detector de QR
   barcodeDetector.setProcessor(new Detector.Processor() {
       @Override
       public void release() {
       }


       @Override
       public void receiveDetections(Detector.Detections detections) {
           final SparseArray barcodes = detections.getDetectedItems();

           if (barcodes.size() > 0) {
               // obtenemos el token
               final String tokenactual = barcodes.valueAt(0).displayValue.toString();

              //***Codigo de EJEMPLO en Retrofit hacemos la peticion al servidor
               RestApiAdapter restApiAdapter = new RestApiAdapter();

               Gson gson = restApiAdapter.convierteGsonDesearilizadorPost();
               EndpointsApi endpointsApi = restApiAdapter.establecerConexionRestApi(gson);
               Call postCall;

               if (children_qr) {
                   postCall = endpointsApi.getNino(tokenactual, UserPreferences.getLastClienteId(QRActiviy.this).toString(), latitude + "", longitude + "");
               } else {
                   postCall = endpointsApi.getProfesor(tokenactual, UserPreferences.getLastClienteId(QRActiviy.this).toString(), latitude + "", longitude + "");
               }
               if (!tokenanterior.equals(tokenactual)) {

                   postCall.enqueue(new Callback() {
                       @Override
                       public void onResponse(Call call, Response response) {

                           postResponse = response.body();
  
                       }

                       @Override
                       public void onFailure(Call call, Throwable t) {
                           Toast.makeText(QRActiviy.this, getResources().getString(R.string.error_conexion), Toast.LENGTH_LONG).show();

                           Intent intent;
                           intent = new Intent(QRActiviy.this, InfoActivity.class);
                           intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
                           startActivity(intent);
                       }
                   });
        
               }


           }
       }
   });

}

Al correr la aplicación, obtendremos una pantalla como la siguiente:

app corriendo con lector qr

Y esto sería todo, una vez que obtenemos el código podemos hacer lo que queramos, generalmente si estamos creando una aplicación personalizada (Ve como crear códigos QR en CodeIgniter), es probable que queramos enviarlo a nuestra aplicación para validarlo o simplemente mostrarlo al usuario mediante un dialog.


Publicidad

Give me for a beer!

Algunos recursos que te pueden interesar

Templates para Android y iOS

Templates para Android y iOS

Generador de launcher para Android sin padding

Generador de launcher para Android sin padding

Paleta de colores para el Material Design

Paleta de colores para el Material Design

Algunos artículos que te pueden interesar

¿Cómo importar una librería (jar) en Android?

¿Cómo importar una librería (jar) en Android?

En este artículo explicaremos algunas de las diferentes forma que hay para importar las librerías JAR en un proyecto Android, utilizando eclipse y el plugin ADT.

Andrés Cruz 21-09-2013

Creando un Navigation Drawer (menú lateral) en Android

Creando un Navigation Drawer (menú lateral) en Android

El Navigation Drawer es un panel que se expande y contrae desde el lado izquierdo de la pantalla y muestra un menú; en esta primera entrada veremos como crear un menú lateral básico en Android.

Andrés Cruz 22-10-2014

Como configurar el proceso de compilación para firmar automáticamente la APK y obtener el certificado SHA1

Como configurar el proceso de compilación para firmar automáticamente la APK y obtener el certificado SHA1

Se explica cómo generar una apk firmada de manera automática al momento de compilar el proyecto y cómo obtener el certificado SHA1 de nuestra aplicación firmada desde Android Studio.

Andrés Cruz 20-04-2017