Solicita permisos de la app

Cada app de Android se ejecuta en una zona de pruebas con acceso limitado. Si una app necesita usar recursos o información ajenos a su propia zona de pruebas, debe solicitar el permiso correspondiente. Para especificar que tu app necesita un permiso, debes incluirlo en el manifiesto de la app y, luego, solicitar que el usuario apruebe cada solicitud durante el tiempo de ejecución (en Android 6.0 y versiones posteriores).

En esta página, se describe cómo usar la biblioteca de compatibilidad de Android para buscar permisos y solicitarlos. A partir de Android 6.0 (API nivel 23), el marco de trabajo de Android proporciona métodos similares, pero el uso de la biblioteca de compatibilidad facilita la compatibilidad con versiones de Android anteriores.

Agrega permisos al manifiesto

En todas las versiones de Android, para declarar que tu app necesita un permiso, coloca un elemento <uses-permission> en el manifiesto de tu app, como elemento secundario del elemento <manifest> de nivel superior. Por ejemplo, una app que necesita acceso a Internet incluiría la siguiente línea en su manifiesto:

    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
            package="com.example.snazzyapp">

        <uses-permission android:name="android.permission.INTERNET"/>
        <!-- other permissions go here -->

        <application ...>
            ...
        </application>
    </manifest>
    

El comportamiento del sistema después de declarar un permiso depende de qué tan sensible sea este. Algunos se consideran "normales", por lo que el sistema los otorga inmediatamente después de la instalación. Otros se consideran "peligrosos", por lo que el usuario debe otorgar el acceso a tu app de manera explícita. Para obtener más información sobre los diferentes tipos de permisos, consulta Niveles de protección.

Cómo verificar si tu app tiene permisos

Si tu app necesita un permiso peligroso, debes verificar si tienes ese permiso cada vez que realices una operación que lo requiera. A partir de Android 6.0 (nivel de API 23), los usuarios pueden revocar permisos desde cualquier app en cualquier momento, aunque la app esté orientada a un nivel de API inferior. Por lo tanto, aunque la app haya usado la cámara el día anterior, no puede asumir que todavía tiene ese permiso.

Para comprobar si tienes un permiso, llama al método ContextCompat.checkSelfPermission(). Por ejemplo, en este fragmento, se muestra cómo verificar si la actividad tiene permiso para realizar operaciones de escritura en el calendario:

Kotlin

    if (ContextCompat.checkSelfPermission(thisActivity, Manifest.permission.WRITE_CALENDAR)
            != PackageManager.PERMISSION_GRANTED) {
        // Permission is not granted
    }
    

Java

    if (ContextCompat.checkSelfPermission(thisActivity, Manifest.permission.WRITE_CALENDAR)
            != PackageManager.PERMISSION_GRANTED) {
        // Permission is not granted
    }
    

Si la app tiene el permiso, el método muestra PERMISSION_GRANTED y la app puede realizar la operación. Si no lo tiene, el método muestra PERMISSION_DENIED y la app debe solicitárselo al usuario de manera explícita.

Solicita permisos

Cuando tu app recibe PERMISSION_DENIED de checkSelfPermission(), debes solicitar el permiso al usuario. Android proporciona varios métodos para hacerlo (por ejemplo, requestPermissions()), como se muestra en el fragmento de código que aparece debajo. Cuando llamas a estos métodos, aparece un diálogo de Android estándar que no se puede personalizar.

La manera en que este se muestra al usuario depende de la versión de Android que ejecute el dispositivo y de la versión de destino de tu app, como se explica en Descripción general de permisos.

Explica la razón por la cual la app necesita permisos

En algunos casos, puede que quieras ayudar al usuario a comprender por qué tu app necesita un permiso. Por ejemplo, si un usuario inicia una app de fotografía probablemente no se sorprenda si esta le solicita permiso para usar la cámara. Sin embargo, es posible que este no comprenda por qué la app busca acceder a la ubicación o los contactos. Antes de que tu app solicite un permiso, debes considerar proporcionar una explicación al usuario. Recuerda que no es bueno abrumarlo con explicaciones; si lo haces, podría frustrarse y desinstalar la app.

Un enfoque que podrías usar consiste en proporcionar una explicación solo si el usuario ya rechazó la solicitud de permiso. Android proporciona un método de utilidad, shouldShowRequestPermissionRationale(), que muestra true si el usuario rechazó la solicitud anteriormente y muestra false si un usuario rechazó un permiso y seleccionó la opción No volver a preguntar en el diálogo de solicitud de permiso, o si una política de dispositivo lo prohíbe.

Si un usuario intenta usar reiteradas veces una funcionalidad que requiere un permiso, pero sigue rechazando la solicitud de este, es probable que no entienda por qué la app lo necesita para brindar esa funcionalidad. En una situación como esta, puede que te convenga mostrar una explicación.

Para obtener asesoramiento adicional sobre cómo crear una buena experiencia del usuario cuando solicites permiso, consulta las Prácticas recomendadas de permisos de la app.

Solicita convertirte en el controlador predeterminado si es necesario

Algunas apps dependen del acceso a información sensible del usuario, relacionada con registros de llamadas y mensajes SMS. Si quieres solicitar los permisos específicos para registros de llamadas y mensajes SMS, y publicar tu app en Play Store, debes solicitar al usuario que configure tu app como controlador predeterminado para una función principal del sistema antes de solicitar estos permisos de tiempo de ejecución.

Para obtener más información sobre los controladores predeterminados, así como orientación sobre cómo mostrar una solicitud de estos a los usuarios, consulta la guía sobre permisos que se usan solo en controladores predeterminados.

Solicita los permisos necesarios

Si tu app aún no tiene el permiso que necesita, esta debe llamar a uno de los métodos requestPermissions() para solicitar los permisos correspondientes. Tu app pasa los permisos que necesita y también un código de solicitud de entero que especificas para identificar esta solicitud de permiso. Este método funciona de forma asíncrona. Se muestra inmediatamente y, una vez que el usuario responde la solicitud, el sistema llama al método de devolución de llamada de la app con los resultados y transmite el mismo código de solicitud que la app transmitió a requestPermissions().

El siguiente código verifica si la app tiene permiso para leer los contactos del usuario. Si no lo tiene, verifica si debiera mostrar una explicación de por qué lo necesita; si no es necesario, entonces solicita el permiso:

Kotlin

    // Here, thisActivity is the current activity
    if (ContextCompat.checkSelfPermission(thisActivity,
            Manifest.permission.READ_CONTACTS)
            != PackageManager.PERMISSION_GRANTED) {

        // Permission is not granted
        // Should we show an explanation?
        if (ActivityCompat.shouldShowRequestPermissionRationale(thisActivity,
                Manifest.permission.READ_CONTACTS)) {
            // Show an explanation to the user *asynchronously* -- don't block
            // this thread waiting for the user's response! After the user
            // sees the explanation, try again to request the permission.
        } else {
            // No explanation needed, we can request the permission.
            ActivityCompat.requestPermissions(thisActivity,
                    arrayOf(Manifest.permission.READ_CONTACTS),
                    MY_PERMISSIONS_REQUEST_READ_CONTACTS)

            // MY_PERMISSIONS_REQUEST_READ_CONTACTS is an
            // app-defined int constant. The callback method gets the
            // result of the request.
        }
    } else {
        // Permission has already been granted
    }
    

Java

    // Here, thisActivity is the current activity
    if (ContextCompat.checkSelfPermission(thisActivity,
            Manifest.permission.READ_CONTACTS)
            != PackageManager.PERMISSION_GRANTED) {

        // Permission is not granted
        // Should we show an explanation?
        if (ActivityCompat.shouldShowRequestPermissionRationale(thisActivity,
                Manifest.permission.READ_CONTACTS)) {
            // Show an explanation to the user *asynchronously* -- don't block
            // this thread waiting for the user's response! After the user
            // sees the explanation, try again to request the permission.
        } else {
            // No explanation needed; request the permission
            ActivityCompat.requestPermissions(thisActivity,
                    new String[]{Manifest.permission.READ_CONTACTS},
                    MY_PERMISSIONS_REQUEST_READ_CONTACTS);

            // MY_PERMISSIONS_REQUEST_READ_CONTACTS is an
            // app-defined int constant. The callback method gets the
            // result of the request.
        }
    } else {
        // Permission has already been granted
    }
    

La solicitud que muestra el sistema describe el grupo de permisos que necesita tu app, pero no el permiso específico.

Nota: Cuando tu app llama a requestPermissions(), el sistema muestra al usuario un cuadro de diálogo estándar. Tu app no puede configurar ni modificar ese cuadro de diálogo. Si necesitas proporcionar información o una explicación al usuario, debes hacerlo antes de llamar a requestPermissions(), como se describe en Explica la razón por la cual la app necesita permisos.

Controla la respuesta a la solicitud de permisos

Cuando el usuario responde la solicitud de permiso de tu app, el sistema invoca el método onRequestPermissionsResult() de tu app y le transmite la respuesta del usuario. Esta debe anular ese método para averiguar si se otorgó el permiso. La devolución de llamada recibe el mismo código de solicitud que le pasaste a requestPermissions(). Por ejemplo, si una app solicita acceso de READ_CONTACTS, es posible que tenga el siguiente método de devolución de llamada:

Kotlin

    override fun onRequestPermissionsResult(requestCode: Int,
            permissions: Array<String>, grantResults: IntArray) {
        when (requestCode) {
            MY_PERMISSIONS_REQUEST_READ_CONTACTS -> {
                // If request is cancelled, the result arrays are empty.
                if ((grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED)) {
                    // permission was granted, yay! Do the
                    // contacts-related task you need to do.
                } else {
                    // permission denied, boo! Disable the
                    // functionality that depends on this permission.
                }
                return
            }

            // Add other 'when' lines to check for other
            // permissions this app might request.
            else -> {
                // Ignore all other requests.
            }
        }
    }
    

Java

    @Override
    public void onRequestPermissionsResult(int requestCode,
            String[] permissions, int[] grantResults) {
        switch (requestCode) {
            case MY_PERMISSIONS_REQUEST_READ_CONTACTS: {
                // If request is cancelled, the result arrays are empty.
                if (grantResults.length > 0
                    && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    // permission was granted, yay! Do the
                    // contacts-related task you need to do.
                } else {
                    // permission denied, boo! Disable the
                    // functionality that depends on this permission.
                }
                return;
            }

            // other 'case' lines to check for other
            // permissions this app might request.
        }
    }
    

El cuadro de diálogo que muestra el sistema describe el grupo de permisos al que tu app necesita acceder, pero no indica el permiso específico. Por ejemplo, si solicitas el permiso READ_CONTACTS, el cuadro de diálogo del sistema solo dice que tu app necesita acceder a los contactos del dispositivo. El usuario solamente tiene que otorgar el permiso una vez para cada grupo de permisos. Si tu app solicita otros permisos de ese grupo (indicados en el manifiesto, el sistema los otorga de manera automática. Cuando solicitas el permiso, el sistema llama a tu método de devolución de llamada onRequestPermissionsResult() y pasa PERMISSION_GRANTED, tal como lo haría si el usuario hubiera aceptado explícitamente tu solicitud a través del cuadro de diálogo del sistema.

Nota: De todos modos, tu app debe solicitar de manera explícita cada uno de los permisos que necesita, aunque el usuario haya otorgado otro del mismo grupo. Además, la agrupación de permisos puede modificarse en futuras versiones de Android. En tu código no debe presuponerse que habrá o no permisos específicos en el mismo grupo.

Por ejemplo, supón que indicas READ_CONTACTS y WRITE_CONTACTS en el manifiesto de tu app. Si solicitas READ_CONTACTS, el usuario concede el permiso y luego solicitas WRITE_CONTACTS, el sistema te otorga de inmediato ese permiso sin interactuar con el usuario.

Si un usuario rechaza una solicitud de permiso, tu app debe tomar una medida adecuada. Por ejemplo, esta podría mostrar un diálogo en el que se explique por qué no podría realizar la acción solicitada por el usuario para la cual se requiere ese permiso.

Cuando el sistema solicita al usuario que otorgue un permiso, este tiene la opción de indicar al sistema que no vuelva a solicitarlo. En ese caso, cuando la app use requestPermissions() para solicitar ese permiso de nuevo, el sistema rechazará la solicitud de inmediato. El sistema llama a tu método de devolución de llamada onRequestPermissionsResult() y pasa PERMISSION_DENIED, tal como lo haría si el usuario hubiera rechazado explícitamente tu solicitud una vez más. También muestra false si una política de dispositivo prohíbe que la app tenga ese permiso. Esto significa que, cuando llamas a requestPermissions(), no puedes suponer que haya existido interacción directa con el usuario.

Si quieres proporcionar la mejor experiencia del usuario al solicitar permisos de la app, también puedes consultar las Prácticas recomendadas de permisos de la app.

Declara permisos por nivel de API

Para declarar permisos únicamente en dispositivos que admiten permisos durante el tiempo de ejecución (es decir, que ejecuten Android 6.0 [API nivel 23] o versiones posteriores), debes incluir la etiqueta uses- permission-sdk-23 en lugar de uses-permission.

Cuando usas cualquiera de estas etiquetas, puedes establecer el atributo maxSdkVersion para especificar que, en dispositivos que ejecutan versiones posteriores, no se necesita ningún permiso en particular.

Recursos adicionales

Para obtener información adicional sobre permisos, consulta los siguientes artículos:

Para obtener más información sobre cómo solicitar permisos, descarga las siguientes apps de ejemplo: