Recomendaciones sobre permisos de la app

Las solicitudes de permisos protegen la información sensible de un dispositivo y solo deben usarse cuando el acceso a la información es necesario para el funcionamiento de tu app. En este documento, se sugieren diferentes maneras de lograr la misma funcionalidad (o mejorarla) sin solicitar acceso a dicha información. Sin embargo, no se aborda de forma exhaustiva el funcionamiento de los permisos en el sistema operativo Android.

Para obtener un panorama general sobre los permisos de Android, consulta la descripción general de permisos. Para obtener información sobre cómo trabajar con permisos en tu código, consulta Cómo solicitar permisos de apps.

Principios básicos del trabajo con permisos de Android

Te recomendamos que sigas estos principios básicos cuando trabajes con permisos de Android:

N.° 1: Solo usa los permisos necesarios para el funcionamiento de tu app. Según la forma en que uses los permisos, puede haber otra alternativa para hacer lo que necesitas (intents de sistema, identificadores, colocación de llamadas telefónicas en segundo plano) sin depender del acceso a información sensible.

N.° 2: Presta atención a los permisos que se requieren para las bibliotecas. Cuando incluyes una biblioteca, también heredas sus requisitos de permisos. Debes tener noción de lo que incluirás, los permisos que se requieren y cuál es su propósito.

N.° 3: Sé transparente. Cuando solicites permisos, sé claro con respecto a la información a la que accedes y la razón por la que lo haces, de manera que los usuarios puedan tomar decisiones fundamentadas. Haz que la información esté disponible junto con la solicitud de permiso que incluya los diálogos correspondientes durante la instalación, el tiempo de ejecución o la actualización.

N.° 4: Explicita los accesos al sistema. Si les indicas continuamente cuando accedes a funciones sensibles (como la cámara o el micrófono), los usuarios verán con claridad los momentos en los que recopiles datos. De esta forma, evitarás la percepción de que lo haces de forma clandestina.

En las secciones restantes de esta guía, se abordan estas reglas con mayor profundidad en el contexto del desarrollo de apps para Android.

Permisos en Android 6.0 y versiones posteriores

Android 6.0 Marshmallow incorporó un nuevo modelo de permisos mediante el cual las apps pueden solicitar permisos a los usuarios durante el tiempo de ejecución, y no antes de la instalación. Las apps que admiten el nuevo modelo solicitan permisos cuando se necesitan los servicios o los datos que estos protegen. Si bien esto no cambia (necesariamente) el comportamiento general de las apps, introduce algunas modificaciones relevantes en la manera en que se manejan los datos sensibles del usuario.

Mayor contexto situacional: En el contexto de tu app, se solicita permiso a los usuarios durante el tiempo de ejecución para acceder a las funcionalidades que abarcan esos grupos de permisos. Los usuarios son más sensibles al contexto en el que se solicita el permiso y, si lo que solicitas no coincide con el propósito de tu app, es incluso más importante proporcionarles una explicación detallada del motivo por el cual necesitas el permiso. Siempre que sea posible, debes proporcionar una explicación de la solicitud, tanto cuando la realizas como en un diálogo de seguimiento (si el usuario la rechaza).

Mayor flexibilidad al otorgar permisos: Los usuarios pueden denegar el acceso a permisos individuales cuando se solicitan y desde la configuración, pero aun así podrían sorprenderse si, en consecuencia, esta opción no funciona. Te recomendamos controlar la cantidad de usuarios que deniegan permisos (p. ej., con Google Analytics), de manera que puedas refactorizar tu app para evitar depender de ese permiso o proporcionar una mejor explicación del motivo por el cual lo necesitas para que tu app funcione correctamente. También debes asegurarte de que este maneje excepciones creadas cuando los usuarios rechacen solicitudes de permisos o los desactiven en la configuración.

Mayor carga de transacciones: Se solicitará a los usuarios que otorguen acceso a grupos de permisos de manera individual y no en conjunto. Esta acción hace que minimizar la cantidad de permisos que solicitas sea sumamente importante, ya que aumenta la carga de otorgamiento de permisos para el usuario y la probabilidad de que se rechace al menos una de las solicitudes.

Permisos que requieren que te conviertas en un controlador predeterminado

Algunas apps dependen del acceso a la información sensible del usuario que se relaciona con sus 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 controlador predeterminado a los usuarios, consulta la guía sobre permisos que se usan solo en controladores predeterminados.

Evita solicitar permisos innecesarios

Cada vez que solicitas un permiso, obligas al usuario a tomar una decisión. Debes reducir al mínimo la cantidad de veces que realizas estas solicitudes. Si el usuario ejecuta Android 6.0 (API nivel 23) o una versión posterior, cada vez que pruebe alguna función de la app que requiera un permiso, esta deberá interrumpir lo que el usuario esté haciendo para solicitarlo. Si ejecuta una versión anterior, deberá otorgar todos los permisos de la app al momento de la instalación. Si la lista es demasiado larga o resulta inapropiada, el usuario podría decidir no instalar la app. Por estos motivos, debes reducir al mínimo la cantidad de permisos que tu app necesita.

En esta sección, se ofrecen alternativas para casos prácticos comunes que te ayudarán a limitar la cantidad de solicitudes de permisos que realices. Como la cantidad y el tipo de permisos solicitados al usuario afectan las descargas, en comparación con otras apps similares que solicitan menos permisos, te recomendamos evitar pedirlos para funcionalidades innecesarias.

Mejor usa un intent

En muchos casos, puedes elegir entre dos formas para que tu app realice una tarea. Puede solicitar permiso para realizar una tarea por sí misma, o bien usar un intent y asignársela a otra app.

Por ejemplo, supongamos que tu app necesita tener la capacidad de tomar fotos con la cámara del dispositivo. Entonces, puede solicitar el permiso CAMERA, que le permitirá acceder directamente a la cámara. De esta manera, tu app usará las API de la cámara para controlarla y tomar una foto. Este enfoque le otorga a tu app el control total del proceso de fotografía y te permite incorporarle la IU de la cámara.

Sin embargo, si la solicitud de acceso a los datos del usuario es poco frecuente (es decir, si al usuario no le molesta que le aparezca un diálogo durante el tiempo de ejecución cada vez que necesites acceder a los datos), puedes usar una solicitud basada en intents. Android proporciona algunos intents del sistema que las apps pueden usar sin solicitar permisos dado que el usuario elige, en todo caso, qué quiere compartir con la app cuando se emite la solicitud basada en intents.

Por ejemplo, un tipo de acción de intent de MediaStore.ACTION_IMAGE_CAPTURE o MediaStore.ACTION_VIDEO_CAPTURE se puede usar para capturar imágenes o videos sin usar directamente el objeto Cámara (o sin solicitar el permiso correspondiente). En este caso, el intent del sistema solicitará permiso al usuario en representación tuya cada vez que se capture una imagen.

De manera similar, si necesitas realizar una llamada telefónica o acceder a los contactos del usuario, entre otras acciones, puedes crear un intent apropiado o bien solicitar el permiso y acceder directamente a los objetos correspondientes. Ambos enfoques tienen ventajas y desventajas.

Si usas permisos, sucede lo siguiente:

  • Tu app controla por completo la experiencia del usuario cuando realizas la operación. Sin embargo, un control tan amplio sumará complejidad a tu código, ya que deberás diseñar una IU acorde.
  • Se solicita permiso al usuario una sola vez, ya sea durante el tiempo de ejecución o la instalación (según la versión de Android que ejecute). Luego, tu app podrá realizar la operación sin requerir interacción adicional por parte del usuario. Pero, si este no otorga el permiso (o lo revoca más adelante), la app ya no podrá realizar la operación.

Si usas un intent, sucede lo siguiente:

  • No debes diseñar la IU para la operación. La app que controla el intent proporciona la IU.
  • El usuario puede usar la app que prefiera para realizar la tarea. Por ejemplo, puede seleccionar la app de fotos que prefiera para tomar una foto.
  • Si el usuario no tiene una app predeterminada para la operación, el sistema le solicitará que seleccione una. Si este no designa un controlador predeterminado, podría abrirse un diálogo adicional cada vez que realice la operación.

No abrumes al usuario

Si el usuario ejecuta Android 6.0 (nivel de API 23) o una versión posterior, deberá otorgar permisos a tu app mientras la ejecuta. Si lo expones a muchas solicitudes de permisos al mismo tiempo, podrías abrumarlo y hacer que deje de usar tu app. Como alternativa, deberías solicitar permisos a medida que los necesites.

Es posible que en algunos casos uno o más permisos sean absolutamente esenciales para tu app. De ser así, te recomendamos solicitar todos los permisos apenas se inicie la app. Por ejemplo, si creas una app de fotografía, podría necesitar acceder a la cámara del dispositivo. Por lo tanto, cuando el usuario inicie la app por primera vez, no se sorprenderá si se le solicita permiso para usar la cámara. Pero si la app tiene además una función para compartir fotos con los contactos del usuario, no deberías solicitar el permiso READ_CONTACTS la primera vez que inicia la app. En su lugar, espera a que el usuario intente utilizar esta función para solicitarlo.

Si tu app incluye un instructivo, te recomendamos solicitar los permisos esenciales cuando finalice la secuencia del tutorial.

Detén el contenido cuando se pierda el foco de audio

En este caso, la app debe ejecutarse en segundo plano cuando el usuario recibe una llamada telefónica y volver a enfocar cuando esta finalice.

El enfoque común en estos casos (por ejemplo, silenciar o pausar el reproductor multimedia durante una llamada) es escuchar los cambios en el estado de la llamada con PhoneStateListener o escuchar la transmisión de android.intent.action.PHONE_STATE. El problema de esta solución es que requiere el permiso READ_PHONE_STATE, que obliga al usuario a otorgar acceso a una amplia variedad de secciones de datos sensibles como los ID de su dispositivo y del hardware de SIM, y el número de teléfono de la llamada entrante. Además, los eventos LISTEN_CELL_LOCATION y LISTEN_CELL_INFO requieren un permiso de ubicación cuando la app se ejecuta en Android 10 (nivel de API 29) o una versión posterior (en particular, ACCESS_FINE_LOCATION si la app se orienta a Android 10 o versiones posteriores).

Puedes detectar si el usuario está realizando una llamada sin los permisos READ_PHONE_STATE o MODIFY_PHONE_STATE si solicitas AudioFocus para tu app, que no requiere permisos explícitos (porque no accede a información sensible). Solo tienes que insertar el código necesario para colocar tu audio en segundo plano en el controlador de eventos onAudioFocusChange(), y se ejecutará automáticamente cuando el SO cambie el foco del audio. Puedes encontrar documentación detallada sobre cómo hacerlo aquí.

Determina el dispositivo en el que se ejecuta tu instancia

En este caso, necesitas un identificador único para determinar en qué dispositivo se está ejecutando la instancia de tu app.

Las apps pueden tener preferencias o mensajería específicas por dispositivo (p. ej., guardar en la nube una lista de reproducción específica del dispositivo de un usuario, de manera que pueda tener varias para su vehículo y el hogar). Una solución común es usar identificadores de dispositivos como Device IMEI, pero para ello se requiere el grupo de permisos Device ID and call information (PHONE en M o versiones posteriores). También usa un identificador que no se puede restablecer y se comparte entre todas las apps.

Hay dos alternativas para usar estos tipos de identificadores:

  1. Usa la API de InstanceID com.google.android.gms.iid. getInstance(Context context).getID() mostrará un identificador de dispositivos único para tu instancia de aplicación. Como resultado, se obtiene un identificador específico de la instancia de la app que se puede usar como clave al almacenar información sobre la app, y se restablece si el usuario vuelve a instalarla.
  2. Crea tu propio identificador específico para el almacenamiento de la app mediante funciones básicas del sistema, como randomUUID().

Crea un identificador único para publicitar o analizar el comportamiento de los usuarios

En este caso, necesitas un identificador único a fin de crear un perfil para los usuarios que no accedieron a tu app (p. ej. para la orientación de anuncios o la medición de conversiones).

La creación de un perfil para publicidad y análisis de los usuarios puede requerir un identificador que se comparte con otras apps. Entre las soluciones comunes para este problema, se incluye el uso de identificadores de dispositivos como Device IMEI, que requiere el grupo de permisos Device IDand call information (PHONE en API nivel 23 o superior) y que el usuario no puede restablecer. En cualquiera de estos casos, además de usar un identificador que no se puede restablecer y solicitar un permiso que pueda parecer extraño a los usuarios, también infringirás las Políticas del Programa para Desarrolladores de Play.

Lamentablemente, en estos casos, el uso de la API de InstanceID de com.google.android.gms.iid o de funciones del sistema para crear un ID específico de la app no son soluciones apropiadas debido a que tal vez debas compartir el ID con otras apps. Como alternativa, puedes usar el elemento Advertising Identifier de la clase AdvertisingIdClient.Info mediante el método getId(). Puedes crear un objeto AdvertisingIdClient.Info por medio del método getAdvertisingIdInfo(Context) y llamar a getId() para que use el identificador. Ten en cuenta que este método es de bloqueo, por lo que no debes llamarlo desde el subproceso principal. Puedes encontrar una explicación detallada de este método aquí.

Conoce las bibliotecas con las que trabajas

Algunas veces, las bibliotecas que usas en tu app requieren permisos. Por ejemplo, es posible que las bibliotecas de anuncios y de análisis requieran acceso a los grupos de permisos LOCATION para implementar la funcionalidad requerida. Sin embargo, desde la perspectiva del usuario, la solicitud de permiso proviene de tu app y no de la biblioteca.

Como los usuarios seleccionan apps que usan menos permisos para la misma funcionalidad, los desarrolladores deben revisar sus bibliotecas y seleccionar SDK de terceros que no soliciten permisos innecesarios. Por ejemplo, si usas una biblioteca que proporciona funcionalidad de ubicación, asegúrate de no solicitar el permiso FINE_LOCATION a menos que estés usando la funcionalidad de orientación basada en la ubicación.

Explica por qué se necesitan los permisos

En el diálogo de permisos que muestra el sistema cuando llamas a requestPermissions(), se especifica qué permisos necesita la app, pero no el motivo. A veces, esto puede confundir al usuario. Te recomendamos explicarle por qué tu app necesita estos permisos antes de llamar a requestPermissions().

Algunas investigaciones muestran que los usuarios se sienten más cómodos con las solicitudes de permisos si saben para qué los necesita la app. Un estudio de usuarios mostró lo siguiente:

La disposición de un usuario para otorgar permiso a una app determinada se ve notablemente afectada por el propósito asociado con ese permiso. Por ejemplo, la disposición de un usuario a otorgar acceso a su ubicación variará en función de si la solicitud se realiza para respaldar la funcionalidad central de la app o para compartir esa información con una red de publicidad o una empresa de análisis de datos.1

Conforme a la investigación de su grupo, el profesor Jason Hong, de la CMU, llegó a la siguiente conclusión:

En general, cuando las personas saben por qué una app usa información sensible, como su ubicación (por ejemplo, para publicidad orientada), se sienten más cómodas que cuando no se les da una explicación.1

En consecuencia, si solo usas una fracción de las llamadas de la API que pertenecen a un grupo de permisos, te será más fácil indicar explícitamente los permisos que usas y por qué. Por ejemplo:

  • Si solo usas la ubicación aproximada, infórmalo al usuario en la descripción de tu app o los artículos de ayuda.
  • Si necesitas acceso a mensajes SMS para recibir códigos de autenticación que protegen al usuario contra fraudes, infórmaselo en la descripción de tu app o la primera vez que accedas a los datos.

    Nota: Si tu app se orienta a dispositivos que ejecutan Android 8.0 (API nivel 26) o una versión posterior, no solicites el permiso READ_SMS como parte de la verificación de las credenciales del usuario. En su lugar, genera un token específico de la app mediante createAppSpecificSmsToken() y, luego, transmítelo a otro servicio o app que pueda enviar un mensaje SMS de verificación.

En ciertos casos, resulta favorable informar a los usuarios respecto del acceso a datos sensibles en tiempo real. Por ejemplo, si accedes a la cámara o al micrófono, se recomienda que se lo informes al usuario con un ícono de notificación en algún sector de tu app, o bien en la bandeja de notificaciones (si la app se ejecuta en segundo plano), de manera que no parezca que recopilas datos de forma clandestina.

Por último, si tienes que solicitar un permiso para realizar alguna tarea en tu app, pero el motivo no está claro para el usuario, busca una manera de informarle por qué necesitas los permisos más sensibles.

Prueba ambos modelos de permisos

A partir de Android 6.0 (API nivel 23), los usuarios otorgan permisos a la app y los revocan durante el tiempo de ejecución, en lugar de hacerlo cuando la instalan. Como consecuencia, deberás probar tu app en una mayor variedad de condiciones. Antes de Android 6.0, era razonable suponer que si tu app estaba en ejecución, era porque contaba con todos los permisos que se declaraban en su manifiesto. A partir de esa versión, el usuario puede habilitar o inhabilitar los permisos de cualquier app, incluso de aquellas que se orientan a API nivel 22 o anteriores. Deberías realizar una prueba para asegurarte de que tu app funciona de manera correcta independientemente de si cuenta o no con los permisos.

Las siguientes sugerencias te ayudarán a encontrar los problemas de código relacionados con los permisos en los dispositivos que ejecutan API nivel 23 o posterior:

  • Identifica los permisos actuales de tu app y las rutas de acceso de códigos relacionadas.
  • Prueba los flujos del usuario en los datos y servicios protegidos por permisos.
  • Prueba con varias combinaciones de permisos otorgados y rechazados. Por ejemplo, es posible que en el manifiesto de una app de cámara se enumeren los permisos CAMERA, READ_CONTACTS y ACCESS_FINE_LOCATION. Debes probar la app con cada uno de estos permisos tanto habilitados como inhabilitados para asegurarte de que la app funciona correctamente con todas las posibles configuraciones.
  • Usa la herramienta de adb para administrar los permisos desde la línea de comandos:
    • Enumera los permisos y estados por grupo:
      $ adb shell pm list permissions -d -g
    • Otorga o revoca uno o más permisos:
      $ adb shell pm [grant|revoke] <permission-name> ...
  • Analiza tu app en busca de servicios que usen permisos.

Recursos adicionales

Referencias

[1] Modeling Users’ Mobile App Privacy Preferences: Restoring Usability in a Sea of Permission Settings ("Cómo modelar las preferencias de privacidad de las apps para dispositivos móviles de los usuarios: restablecimiento de la usabilidad en un mar de configuraciones de permisos"), de J. Lin B. Liu, N. Sadeh y J. Hong. En actas de SOUPS 2014.