Android Dev Summit, October 23-24: two days of technical content, directly from the Android team. Sign-up for livestream updates.

Cambio en la privacidad de Android Q: el usuario controla el acceso que tiene la app con respecto a la ubicación del dispositivo

A partir de la versión Beta 5 de Android Q, este cambio tiene las siguientes propiedades:

  • Afecta tu app si solicitas acceso a la ubicación del dispositivo cuando está en segundo plano.
  • El usuario podría recibir un recordatorio luego de permitir que una app acceda a la ubicación del dispositivo en segundo plano.
  • Puedes reducir los efectos de este cambio usando nuevos permisos para acceder a la ubicación mientras la app está en segundo plano y asegurándote de usar degradación elegante ante la falta de actualizaciones de ubicación en segundo plano.
  • El comportamiento siempre está habilitado en Android Q.

Nos interesan tus comentarios. Informa los problemas que encuentres mientras usas esta función durante el programa de la versión Beta de Android Q.

Captura de pantalla del diálogo para el usuario
Figura 1: Diálogo que solicita la confirmación del usuario para acceder a la ubicación

Android Q les permite a los usuarios controlar cuándo las apps pueden acceder a la ubicación del dispositivo. Cuando una app ejecutada en Android Q solicita acceder a la ubicación, los usuarios ven el diálogo de la Figura 1, que les permite otorgar acceso a la ubicación de dos maneras: cuando la app está en uso (solo en primer plano) o todo el tiempo (en primer y segundo plano).

Además, para darles a los usuarios más control sobre el acceso que una app tiene a esta información, Android Q presenta un nuevo permiso de ubicación: ACCESS_BACKGROUND_LOCATION. A diferencia de los permisos ACCESS_FINE_LOCATION y ACCESS_COARSE_LOCATION existentes, este nuevo permiso solo afecta el acceso a la ubicación cuando la app está en segundo plano. A menos que una de sus actividades esté visible o que la app ejecute un servicio en primer plano, se considera que está en segundo plano.

Cómo solicitar ubicación en segundo plano

Si tu app se orienta a Android Q y necesita acceder a la ubicación del dispositivo cuando se ejecuta en segundo plano, tienes que declarar el permiso nuevo en el archivo de manifiesto de tu app:

    <manifest>
      <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
      <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
    </manifest>
    

Si tu app se ejecuta en Android Q, pero se orienta a Android 9 (nivel de API 28) o versiones anteriores, aplica el siguiente comportamiento:

Cómo solicitar acceso a la ubicación en segundo plano

Si el caso práctico de tu app necesita acceder a la información de la ubicación cuando se ejecuta en segundo plano, es importante considerar el alcance de ese acceso:

  • El caso práctico de tu app se basa en una continuación de una acción iniciada por el usuario, como una acción de navegación o de hogar inteligente. En ese caso, aunque el usuario haya solicitado que tu app tenga acceso a su ubicación solo en primer plano, configura tu servicio en primer plano para que pueda retener el acceso a la ubicación de un dispositivo después de que el usuario presione el botón de inicio o apague la pantalla.
  • El caso práctico de tu app se basa en controles regulares de la ubicación de un dispositivo todo el tiempo, como geovallado o compartir ubicación. En ese caso, tu app tendrá que explicarle al usuario que debe otorgarle acceso a la ubicación del dispositivo todo el tiempo para funcionar correctamente y luego solicitar acceso a la ubicación en segundo plano.

Continuación de la acción iniciada por el usuario

Nota: Si tu app no necesita acceder a la ubicación mientras se ejecuta en segundo plano, te recomendamos que la orientes a Android Q y no solicites el nuevo permiso de ubicación en segundo plano. De esta manera, tu app solo recibirá actualizaciones de ubicación cuando el usuario la esté utilizando.

En el proyecto LocationUpdatesForegroundService en GitHub, se muestra un ejemplo de ese tipo de app.

Cuando el usuario le haya dado a tu app acceso a la ubicación solamente en primer plano, es posible que el usuario inicie un flujo de trabajo que requiera que tu app acceda a su ubicación, incluso después de presionar el botón de inicio en el dispositivo o apagar la pantalla.

Para retener el acceso a la ubicación del dispositivo en este caso práctico, inicia un servicio en primer plano que hayas declarado que tiene un tipo de servicio en primer plano de "location" en el manifiesto de tu app:

    <service
        android:name="MyNavigationService"
        android:foregroundServiceType="location" ... >
        ...
    </service>
    

Antes de iniciar el servicio en primer plano, asegúrate de que la app aún tenga acceso a la ubicación del dispositivo:

Kotlin

    val permissionAccessCoarseLocationApproved = ActivityCompat
        .checkSelfPermission(this, permission.ACCESS_COARSE_LOCATION) ==
        PackageManager.PERMISSION_GRANTED

    if (permissionAccessCoarseLocationApproved) {
       // App has permission to access location in the foreground. Start your
       // foreground service that has a foreground service type of "location".
    } else {
       // Make a request for foreground-only location access.
       ActivityCompat.requestPermissions(this,
           arrayOf(Manifest.permission.ACCESS_COARSE_LOCATION),
           your-permission-request-code
       )
    }
    

Java

    boolean permissionAccessCoarseLocationApproved =
        ActivityCompat.checkSelfPermission(this,
            permission.ACCESS_COARSE_LOCATION) ==
            PackageManager.PERMISSION_GRANTED;

    if (permissionAccessCoarseLocationApproved) {
        // App has permission to access location in the foreground. Start your
        // foreground service that has a foreground service type of "location".
    } else {
       // Make a request for foreground-only location access.
       ActivityCompat.requestPermissions(this, new String[] {
            Manifest.permission.ACCESS_COARSE_LOCATION},
           your-permission-request-code);
    }
    

Controles regulares de la ubicación del dispositivo

Tu app puede tener un caso práctico que necesite acceso a la ubicación del dispositivo todo el tiempo. Por ejemplo, geovallado y compartir ubicación con amigos y familiares.

De ser así, puedes continuar solicitando actualizaciones de la ubicación sin realizar ningún cambio, siempre que el usuario le dé permiso a tu app para acceder a su ubicación todo el tiempo:

En el siguiente fragmento de código, se muestra cómo declarar un servicio que solicita acceso a la ubicación del dispositivo todo el tiempo:

    <!-- It's unnecessary to include a foreground service type for services that must have
         access to the device's location "all the time" in order to run successfully.-->
    <service
        android:name="MyFamilyLocationSharingService" ... >
        ...
    </service>
    

En el proyecto LocationUpdatesPendingIntent en GitHub, se muestra un ejemplo de ese tipo de app.

Captura de pantalla de la notificación del sistema
Figura 2: Notificación que recuerda al usuario que otorgó a una app permiso de acceso a la ubicación del dispositivo "todo el tiempo".

Cada vez que el usuario otorga acceso a la ubicación del dispositivo "todo el tiempo", el sistema programa el envío de una notificación al usuario a fin de recordarle que otorgó a tu app acceso a la ubicación del dispositivo todo el tiempo. En la figura 2, se muestra una notificación de ejemplo.

Aunque la app puede solicitar acceso a la ubicación en segundo plano, el usuario puede elegir reducir el acceso en segundo plano únicamente o revocar el acceso por completo. Por eso, cuando tu app inicie un servicio, verifica que el usuario aún le permita acceder a la información de la ubicación en segundo plano.

Si el usuario solicitó que tu app acceda solo a la ubicación en primer plano, te recomendamos que tu app muestre un diálogo personalizado para informarle que la app no puede funcionar correctamente sin acceder a la ubicación todo el tiempo. Una vez que el usuario acepte este diálogo, podrás solicitar la ubicación en segundo plano y, luego, aparecerá el diálogo que se muestra en la figura 3:

Captura de pantalla del diálogo para el usuario
Figura 3: Diálogo que le solicita al usuario permitir el acceso a la ubicación todo el tiempo

A continuación, hay un ejemplo de esta lógica de verificación de permiso:

Kotlin

    val permissionAccessCoarseLocationApproved = ActivityCompat
        .checkSelfPermission(this, permission.ACCESS_COARSE_LOCATION) ==
        PackageManager.PERMISSION_GRANTED

    if (permissionAccessCoarseLocationApproved) {
       val backgroundLocationPermissionApproved = ActivityCompat
           .checkSelfPermission(this, permission.ACCESS_BACKGROUND_LOCATION) ==
           PackageManager.PERMISSION_GRANTED

       if (backgroundLocationPermissionApproved) {
           // App can access location both in the foreground and in the background.
           // Start your service that doesn't have a foreground service type
           // defined.
       } else {
           // App can only access location in the foreground. Display a dialog
           // warning the user that your app must have all-the-time access to
           // location in order to function properly. Then, request background
           // location.
           ActivityCompat.requestPermissions(this,
               arrayOf(Manifest.permission.ACCESS_BACKGROUND_LOCATION),
               your-permission-request-code
           )
       }
    } else {
       // App doesn't have access to the device's location at all. Make full request
       // for permission.
       ActivityCompat.requestPermissions(this,
           arrayOf(Manifest.permission.ACCESS_COARSE_LOCATION,
                   Manifest.permission.ACCESS_BACKGROUND_LOCATION),
           your-permission-request-code
       )
    }
    

Java

    boolean permissionAccessCoarseLocationApproved =
        ActivityCompat.checkSelfPermission(this, permission.ACCESS_COARSE_LOCATION)
            == PackageManager.PERMISSION_GRANTED;

    if (permissionAccessCoarseLocationApproved) {
       boolean backgroundLocationPermissionApproved =
               ActivityCompat.checkSelfPermission(this,
                   permission.ACCESS_BACKGROUND_LOCATION)
                   == PackageManager.PERMISSION_GRANTED;

       if (backgroundLocationPermissionApproved) {
           // App can access location both in the foreground and in the background.
           // Start your service that doesn't have a foreground service type
           // defined.
       } else {
           // App can only access location in the foreground. Display a dialog
           // warning the user that your app must have all-the-time access to
           // location in order to function properly. Then, request background
           // location.
           ActivityCompat.requestPermissions(this, new String[] {
               Manifest.permission.ACCESS_BACKGROUND_LOCATION},
               your-permission-request-code);
       }
    } else {
       // App doesn't have access to the device's location at all. Make full request
       // for permission.
       ActivityCompat.requestPermissions(this, new String[] {
            Manifest.permission.ACCESS_COARSE_LOCATION,
            Manifest.permission.ACCESS_BACKGROUND_LOCATION
            },
            your-permission-request-code);
    }
    

Cómo diseñar para casos donde se actualiza el dispositivo

Si un usuario completa los siguientes pasos:

  1. Instala tu app en un dispositivo que ejecute Android 9 (nivel de API 28).
  2. Otorga a tu app acceso a la ubicación del dispositivo, ya sea ACCESS_COARSE_LOCATION o ACCESS_FINE_LOCATION.
  3. Actualiza su dispositivo de Android 9 a Android Q.

… entonces el sistema actualiza automáticamente el estado del permiso de ubicación predeterminado de tu app en función de la versión del SDK de destino y sus permisos definidos, como se muestra en la siguiente tabla:

Tabla 1. Cambios en el estado del permiso de ubicación luego de que un dispositivo se actualiza a Android Q

Versión del SDK de destino ¿Se otorgó permiso de ubicación
general o específica?
¿Se definió el permiso en
segundo plano en el manifiesto?
Estado actualizado del permiso predeterminado
Android Q Acceso en primer y segundo plano
Android Q No Acceso en primer plano únicamente
Android Q No (Ignorado por el sistema) Sin acceso
Android 9 o anterior Agregado automáticamente por el sistema durante la actualización del dispositivo Acceso en primer y segundo plano
Android 9 o anterior No (Ignorado por el sistema) Sin acceso

Nota: Incluso después de que el sistema actualiza automáticamente el acceso de tu app a la ubicación del dispositivo, el usuario puede modificar el nivel de acceso. Podría reducir el acceso de tu app a primer plano únicamente o revocarlo por completo.

Por este motivo, antes de acceder a las actualizaciones de ubicación del dispositivo, sigue las prácticas recomendadas para comprobar si el usuario aún permite que tu app reciba la información de ubicación.

Sigue las prácticas recomendadas sobre la ubicación

Al verificar y solicitar permisos de ubicación como se indica en esta guía, tu app puede llevar un registro de su nivel de acceso a la ubicación de dispositivos.

Para obtener más información sobre cómo proteger los datos de los usuarios, consulta la guía de prácticas recomendadas sobre permisos.

Solicita únicamente los permisos que necesites

Solicita permisos solo cuando los necesites. Por ejemplo:

  • No solicites un permiso de ubicación cuando se inicia la app, a menos que sea absolutamente necesario.
  • Si tu app se orienta a Android Q y necesita acceder a la ubicación solo en segundo plano, no solicites ACCESS_BACKGROUND_LOCATION.

Admite la degradación elegante si no recibes el permiso

Para fomentar una buena experiencia del usuario, diseña tu app a fin de que administre correctamente las siguientes situaciones:

  • Tu app no tiene acceso a la información sobre la ubicación.
  • Tu app no tiene acceso a la información sobre la ubicación en segundo plano.

Recursos adicionales

Para obtener más información sobre los cambios relacionados con el acceso de una app a la ubicación del dispositivo, consulta los siguientes recursos adicionales:

Muestras