Cómo pedir permisos en tiempo de ejecución

Los permisos en Android son una parte esencial de cada aplicación, y gracias a ellos puedes acceder a diferentes datos del usuario o hardware del dispositivo. Por ello, es importante que aprendas a pedir permisos en tiempo de ejecución cada vez que el usuario acceda a una función específica.

A día de hoy, debido a las funciones que ejecutan las aplicaciones, prácticamente todas ellas necesitan declarar algún tipo de permiso, ya sea la conexión a Internet, el acceso a la cámara o al GPS, o a los datos de usuario como los contactos, el registro de llamadas o el acceso al correo electrónico y sus cuentas.

Hagamos un repaso rápido sobre la declaración de permisos en Android.

Permisos de aplicaciones Android

Desde los inicios de Android, toda aplicación ha ido acompañada de un conocido archivo llamado ‘Manifest.xml‘. En este archivo se almacenan una serie de datos básicos relacionados con la aplicación. Entre ellos encontramos el nombre de la app, su icono, la Activity inicial, y sí, sus permisos. El archivo Manifest.xml tiene un aspecto como este:

Si te has fijado en la 4ta línea, se define el permiso de acceso a la cámara del dispositivo.

Las declaraciones de permisos en el archivo Manifest.xml son de lo más sencillas. Basta con incluir una nueva línea dentro del primer nivel de las etiquetas <manifest>. En esta nueva línea hay que incluir la etiqueta <uses-permission /> en la que añadiremos el valor «android:name» seguido del permiso a declarar. Te dejo por aquí el enlace a todos los permisos de Android.

Si aún te estás preguntando dónde está el maldito archivo Manifest.xml, podrás encontrarlo en tu explorador de proyecto con la vista de Android, dentro de la carpeta Manifests:

Bien, hasta Android 6 (API 23) esto es lo único que había que hacer. Se declaraban los permisos en el archivo Manifest.xml y el usuario los aceptaba todos al momento de instalar la app en su dispositivo.

A partir de Android 6 se introdujo el sistema de solicitud de permisos en tiempo de ejecución. Es decir, que ahora hay que solicitar permiso al usuario en el momento previo de ejecutar una función determinada ‘dentro de la app’.

Y esto es precisamente lo que vamos a ver ahora, no sin antes conocer el ciclo de vida de la solicitud de permisos.

Ciclo de ejecución de solicitud de permisos

Como te comentaba antes, siempre se han declarado los permisos necesarios en el archivo Manifest.xml, y eso no ha cambiado, hay que seguir declarándolos todos en el mismo archivo. Además, a partir de Android 6 (API 23) hay que añadir un determinado código en la aplicación antes de utilizar cualquier función o hardware específico que lo requiera. Veamos el ciclo de solicitud de permisos:

Como verás, todo empieza en el archivo Manifest, en este caso vamos a tomar como ejemplo que nuestra app tiene que acceder a la cámara del dispositivo. Para ello, primero de todo se declara el permiso de cámara en el archivo Manifest (como en el ejemplo de código más arriba):

<uses-permission android:name="android.permission.CAMERA"/>

Cuando el usuario quiera hacer uso de la cámara habrá que comprobar si se ha otorgado el permiso. En caso favorable, se puede acceder a la cámara directamente.

En caso contrario, si el usuario aún no ha otorgado el permiso habrá que solicitarlo. En función de su respuesta se hará una cosa u otra.

Si acepta el permiso se le mostrará directamente la cámara, sino habría que explicarle «la necesidad» del permiso para que la app funcione correctamente, y posteriormente volver a solicitarle el permiso.

Cómo comprobar los permisos

Para comprobar la aprobación de un permiso, vamos a hacer uso del método ContextCompat.checkSelfPermission(). A este método hay que darle 2 parámetros:

  • Contexto : Con el contexto de la actividad donde se llama al método
  • String : Cadena de texto que identifica el permiso a comprobar

Siguiendo el ejemplo de la app, la comprobación del permiso de cámara quedaría así:

if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED) {}

El método ‘checkSelfPermission‘ puede devolver 2 resultados:

Si recibimos PERMISSION GRANTED todo está correcto y nuestra app puede mostrar la nueva Activity que contiene una ‘preview‘ de la cámara. En caso contrario será necesario pedir el permiso correspondiente.

Cómo pedir permisos en tiempo de ejecución

En caso que el método checkSelfPermission devuelva PERMISSION_DENIED será el momento de solicitar el permiso al usuario. Antes de empezar con la solicitud del permiso, deberás comprobar si hay necesidad de dar una explicación racional al usuario.

En este caso, una explicación racional podría ser que ‘La app necesita acceder a tu cámara para poder escanear los productos’ (por ejemplo).

Esto es básicamente una explicación que se le da al usuario para que comprenda la necesidad de acceder a la cámara.

No todos los permisos tienen necesidad de explicación, por ello es el propio sistema el que se encarga de determinar si el permiso necesita una explicación racional o no. Esto se logra con el método shouldShowRequestPermissionRationale, que devolverá TRUE o FALSE en función de la necesidad de dar una explicación.

En este ejemplo (aunque no es necesario) he creado un AlertDialog que muestra un mensaje de información al usuario al comprobar shouldShowRequestPermissionRationale, aunque en este caso siempre devuelve FALSE:

Como ves, en caso que el método shouldShowRequestPermissionRationale devolviera TRUE, se mostraría un AlertDialog con un texto explicativo, y en el momento de pulsar el botón ‘Continuar’ del AlertDialog se procede a la solicitud del permiso.

En caso que el método shouldShowRequestPermissionRationale devuelva FALSE se solicitará directamente el permiso al usuario.

Habrás podido observar que se incluye una variable llama «PERMISO_CAMARA» en la solicitud del permiso. Esta variable es un entero ‘int’ que sirve de identificador a la solicitud del permiso, está declarada al principio del código de la siguiente manera:

private static final int PERMISO_CAMARA = 0;

Esta variable nos servirá a la hora de comprobar si el permiso se ha aceptado o no.

Actuando a la respuesta del usuario en la solicitud de permiso

Hasta ahora has aprendido a comprobar un permiso, solicitarlo y en determinado caso dar una explicación al usuario, pero… ¿Cómo controlo la respuesta del usuario a la solicitud del permiso?

Toda la magia ocurre en el método onRequestPermissionsResult que deberás añadir a tu Activity:

Este método es llamado automáticamente por el sistema cuando el usuario acepta o denega un permiso. El método viene acompañado de 3 parámetros:

  • int requestCode
  • @NonNull String[] permissions
  • @NonNull int[] grantResults

Para comprobar que el permiso que hemos solicitado ha sido aceptado, vamos a valernos de los 3 parámetros que tenemos. Para ello, primero de todo debemos comprobar que el RequestCode sea igual al que hemos indicado en la solicitud del permiso:

if (requestCode == PERMISO_CAMARA)

Si esto devuelve TRUE, comprobaremos si hay resultados en la array ‘grantResults’ y si el primer resultado corresponde a PERMISSION_GRANTED:

if (grantResults.length == 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED)

Si se dan estos 2 casos quiere decir que el usuario ha aceptado el permiso de cámara solicitado, y podemos proceder a mostrar la siguiente Activity.

En caso contrario, si alguno de estos 2 ‘if’ devuelve FALSE, quiere decir que el usuario no ha aceptado el permiso, y en este caso deberás mostrarle un mensaje al usuario indicándole que para que la app funcione correctamente es necesario otorgar dicho permiso.

Código de ejemplo completo

Para este ejemplo, he creado una sencilla interfaz con 1 botón que se encargará de ejecutar la comprobación de los permisos, y en caso favorable, mostrará una segunda Activity que contendría una vista previa de la cámara:

package com.example.ejemplopermisos;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;

import android.Manifest;
import android.content.DialogInterface;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.view.View;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {

    private static final int PERMISO_CAMARA = 0;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        findViewById(R.id.btn_camara).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //El usuario quiere abrir la cámara, vamos a comprobar primero si tiene el permiso
                ComprobarPermisos();
            }
        });
    }


    private void ComprobarPermisos() {
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA)
                == PackageManager.PERMISSION_GRANTED) {

            /* Ya se ha obtenido el permiso previamente
            Iniciamos Cámara*/

            IniciarCamara();

        } else {
            // No se tiene el permiso, es necesario pedirlo al usuario
            PedirPermisoCamara();
        }
    }

    private void PedirPermisoCamara() {
        //Comprobación 'Racional'
        if (ActivityCompat.shouldShowRequestPermissionRationale(this,
                Manifest.permission.CAMERA)) {

            //Mostramos un AlertDialog al usuario explicándole la necesidad del permiso
            AlertDialog AD;
            AlertDialog.Builder ADBuilder = new AlertDialog.Builder(MainActivity.this);
            ADBuilder.setMessage("Para escanear un producto es necesario utilizar la cámara de tu dispositivo. Permite que 'nombre app' pueda acceder a la cámara.");
            ADBuilder.setPositiveButton("Continuar", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {

                    /*Cuando el usuario pulse sobre el botón del AlertDialog se procede a solicitar
                     el permiso con el siguiente código:*/

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

            //Mostramos el AlertDialog
            AD = ADBuilder.create();
            AD.show();


        } else {
            /*Si no hay necesidad de una explicación racional, pasamos a solicitar el
            permiso directamente*/
            ActivityCompat.requestPermissions(
                    MainActivity.this,
                    new String[]{Manifest.permission.CAMERA},
                    PERMISO_CAMARA);
        }


    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
                                           @NonNull int[] grantResults) {

        if (requestCode == PERMISO_CAMARA) {
            /* Resultado de la solicitud para permiso de cámara
             Si la solicitud es cancelada por el usuario, el método .lenght sobre el array
             'grantResults' devolverá null.*/

            if (grantResults.length == 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {

                // Permiso concedido, podemos iniciar camara

                IniciarCamara();

            } else {
                /* Permiso no concedido
                 Aquí habría que explicar al usuario el por qué de este permiso
                 y volver a solicitarlo .*/
//
            }
        }
    }

    private void IniciarCamara() {
        Toast.makeText(MainActivity.this, "Abriendo cámara...", Toast.LENGTH_SHORT).show();
//        Intent intent = new Intent(this, ActivityCamara.class);
//        startActivity(intent);
    }
}

Y aquí te dejo un vídeo demostrativo del código de arriba:

Con todo esto ya debería saber cómo comprobar los permisos en Android, cómo solicitarlo en caso necesario y cómo controlar la respuesta del usuario frente a la solicitud del permiso.

Si te ha gustado el artículo, me ayudarás mucho si lo compartes con tus amigos en las redes sociales. Si tienes alguna duda o problema a la hora de solicitar los permisos en Android cuéntamelo en los comentarios.

Mario Camí

Desarrollador de aplicaciones Android. Amante de todo lo Open Source, de los videojuegos y nuevas tecnologías. En mi tiempo libre comparto todo lo aprendido y lo que aprendo en el desarrollo de Android a modo de artículo en el blog. La información nos hará libres!

También te podría gustar...