Diálogo de Android que solicita permisos

Android 6: Ejemplo de solicitud de permisos en tiempo de ejecución

Usar requestPermissions y onRequestPermissionsResult para pedir permisos en Android

A partir de la versión 6 de Android, los permisos “riesgosos” deben ser requeridos en tiempo de ejecución y no poniéndolos simplemente en el manifiesto de nuestra app. Citando a Android Developers:

En aquellas de tus apps que estén orientadas a Android 6.0 (nivel de API 23) o versiones posteriores, asegúrate de comprobar y solicitar los permisos en tiempo de ejecución. Para determinar si se concedió un permiso a tu app, llama al nuevo método checkSelfPermission(). Para solicitar un permiso, llama al nuevo método requestPermissions(). Incluso cuando tu app no tenga como objetivo Android 6.0 (nivel de API 23), debes probarla de acuerdo con el nuevo modelo de permisos.

Para muchas personas esto es un poco complejo y enredado, por ello es que hoy vengo a explicar cómo funcionan los permisos a partir de Android 6 y dar algunos ejemplos.

Aplicación de prueba

Para reforzar todo esto he creado una aplicación de ejemplo que pide permiso para acceder a la cámara y al almacenamiento externo al hacer click en determinado botón.

En los dispositivos con sistema operativo Android versión 6 o superior, se mostrará la petición de permiso en tiempo de ejecución:

Diálogo de Android que solicita permisos
Diálogo de Android que solicita permisos

En cambio, para los dispositivos con una versión anterior, se pedirán en tiempo de instalación:

Solicitud de permisos en tiempo de instalación
Solicitud de permisos en tiempo de instalación

Además de que los permisos estarán concedidos desde que se abre la app:

Permisos para la cámara concedidos
Permisos para la cámara concedidos

Código fuente y descargas

Puedes explorar el código fuente en GitHub, aunque la parte importante es el manifiesto y la actividad principal.

Todo eso que se ve en el código lo voy a explicar, pero ahí dejo la prueba de que esto funciona.

Para obtener la aplicación ve a la sección de releases y elige descargar el archivo APK, o clona el repositorio y compila la app por ti mismo.

Un poco de lectura sobre la seguridad

Como desarrolladores, nos vamos a quejar al inicio; pero después de entender esto vamos a ver por qué hace falta.

Hace tiempo, los permisos se pedían al instalar la aplicación. El sistema te indicaba que, por ejemplo, dicha app iba a acceder a la cámara y a tu ubicación. Tú como usuario lo leías pero no sabías en qué momento iba a usar esos recursos, o a veces ni lo leías y aceptabas.

Esto daba paso a muchos ataques que no puedo escribir ahora, pero se me ocurre uno: desarrollar una aplicación que tenga acceso a tu ubicación y al envío de SMS‘s; me prestas tu teléfono un momento, la instalo, acepto los permisos y te lo devuelvo.

Tú nunca sabrás qué hice con él, además de que puedo esconder la app y hacer que se ejecute en segundo plano; para más tarde espiarte y enviarme todo por SMS.

Además, estamos viendo esto del lado del informático. ¿Qué pasa con el usuario final? él no es un experto en sistemas, ni seguridad, ni programación.

Por ello es que, para hacer más seguro todo el entorno, Android introduce estas solicitudes de permisos que ahora se piden en tiempo de ejecución, y no en tiempo de instalación.

Sobre el manifiesto o AndroidManifest.xml

Recuerda que aunque los permisos van a ser solicitados en tiempo de ejecución, debes indicar a los mismos en el AndroidManifest.xml forzosamente; si no, los permisos serán denegados sin pedirle interacción al usuario.

Los paquetes que debemos importar

Para poder solicitar permisos y comprobar a los mismos, además de evitar comprobar la versión de Android para ver si es necesario pedir permisos en tiempo de ejecución son android.support.v4.content.ContextCompat y android.content.pm.PackageManager.

Te digo de nuevo, ve al código fuente para ver cómo se incluyen.

Los permisos en Android

Para ver si ya tenemos un permiso, se llama al método checkSelfPermission de ContextCompat, más adelante veremos sobre esto pero ahora un poco de teoría. Los permisos son concedidos de 2 maneras:

  • Cuando solicitamos el permiso y el usuario lo concede
  • Cuando el usuario va a los detalles de la app y modifica los permisos

Por ello es que no en todas las ocasiones vamos a necesitar pedir permisos, pues el usuario igualmente podría haberlos concedido desde antes.

Permisos de una app de Android
Permisos de una app de Android

Esto es un arma de dos filos (¿o cómo era?) porque igualmente el usuario puede ir a ese apartado y denegar los permisos. Por eso es que siempre debemos verificar los permisos cuando se va a realizar una acción que los requiera, aunque ya los hayan concedido.

Comprobar permisos

Ahora sí, para comprobar permisos llamamos a ContextCompat.checkSelfPermission, que recibe 2 argumentos:

  1. El contexto
  2. Una cadena indicando el permiso que se comprueba; debe ser tomada de Manifest.permission.

Devuelve un entero que puede ser PackageManager.PERMISSION_GRANTED o PackageManager.PERMISSION_DENIED.

En caso de que el usuario haya concedido el permiso anteriormente o estemos en una versión de Android menor al 6, entonces el resultado será PERMISSION_GRANTED.

Por otro lado, si es PERMISSION_DENIED deberíamos pedir el permiso o poner una bandera en false, para desactivar futuras características que requieren el permiso.

Aquí un ejemplo de comprobación de permiso:

// Recuerda: MainActivity es el nombre de tu actividad
int estadoDePermiso = ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.CAMERA);
if (estadoDePermiso == PackageManager.PERMISSION_GRANTED) {
    // Aquí el usuario dio permisos para acceder a la cámara
} else {
    // Si no, entonces pedimos permisos...
}

Lo que se comprueba es el permiso de acceder a la cámara.

Pedir permisos en Android

Para pedir un permiso, llamamos a requestPermissions. Si en el ejemplo anterior el resultado no fuera PERMISSION_GRANTED entonces llamaríamos a este método.

Por cierto, para pedir cada permiso debemos definir unos números identificadores. Son números enteros que nosotros inventamos; no deben repetirse y funcionan para cuando el sistema nos llama en onRequestPermissionsResult.

Veamos un ejemplo para pedir el permiso de acceder a la cámara. En la parte de arriba definimos el código:

private static final int CODIGO_PERMISOS_CAMARA = 1;

En este caso le doy el valor de 1, si hubiera más permisos se pondrían con otros nombres de constantes. Como decía, el código para pedir permisos es:

ActivityCompat.requestPermissions(MainActivity.this,
  new String[]{Manifest.permission.CAMERA},
  CODIGO_PERMISOS_CAMARA);

El método requestPermissions recibe:

  1. El contexto
  2. Un arreglo de permisos que solicitamos
  3. El código de solicitud definido por nosotros

Aquí igualmente podríamos pedir más permisos, pero no lo haremos porque una buena práctica es pedir cada permiso por separado cuando se vaya a usar.

Al llamar este método no se sabe si el usuario denegó o concedió, es decir, el método no devuelve algo que nos importe. En su lugar, muestra al usuario el diálogo que pide permiso:

Diálogo de Android que solicita permisos
Diálogo de Android que solicita permisos

Después de que el usuario rechace o permita cada permiso (en este caso solamente es uno) se llamará al método onRequestPermissionsResult que veremos más abajo.

Nota: todo eso está en vivo dentro de la actividad principal.

Sobrescribir onRequestPermissionsResult

Este método será llamado cuando el usuario termine de aceptar o denegar los permisos, y se le pasan algunos argumentos en el siguiente orden:

  1. requestCode: el código único que le pasamos al pedirle permisos, es un entero
  2. permissions: los permisos que solicitamos en un arreglo de cadenas
  3. grantResults: un arreglo de enteros que pueden ser PERMISSION_GRANTED o PERMISSION_DENIED

Debemos sobrescribir el método y comparar el código de petición, o sea el requestCode. Igualmente debemos verificar si el permiso fue dado o denegado. Aquí un ejemplo de código para el permiso de la cámara:

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    switch (requestCode) {
        case CODIGO_PERMISOS_CAMARA:
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                permisoDeCamaraConcedido();
            } else {
                permisoDeCamaraDenegado();
            }
            break;
        // Aquí más casos dependiendo de los permisos
        // case OTRO_CODIGO_DE_PERMISOS...
    }
}

El método puede devolver arreglos vacíos a veces, cuando el usuario interrumpe la solicitud. Por ello es que comprobamos que su length sea mayor a 0 (que tenga elementos) y que en su primera posición (pues solamente pedimos un permiso a la vez) sea PERMISSION_GRANTED.

En caso de que sea denegado, podemos seguir pidiendo el permiso. Android recomienda que antes de solicitar el permiso se explique por qué se solicita, para que el usuario no desconfíe.

Conclusión

De esta manera pudimos comprobar si tenemos permisos, además de solicitarlos en cualquier versión del sistema operativo Android; ya sea en los que se requieren en tiempo de ejecución o en los que se requieren al instalar.

Te invito y animo a ver más tutoriales sobre Android, Java o Seguridad.

Por cierto, recuerda que todo el código fuente está en mi GitHub.

Estoy aquí para ayudarte 🤝💻


Estoy aquí para ayudarte en todo lo que necesites. Si requieres alguna modificación en lo presentado en este post, deseas asistencia con tu tarea, proyecto o precisas desarrollar un software a medida, no dudes en contactarme. Estoy comprometido a brindarte el apoyo necesario para que logres tus objetivos. Mi correo es parzibyte(arroba)gmail.com, estoy como@parzibyte en Telegram o en mi página de contacto

No te pierdas ninguno de mis posts 🚀🔔

Suscríbete a mi canal de Telegram para recibir una notificación cuando escriba un nuevo tutorial de programación.

Dejar un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *