1. Antes de comenzar
Android 10 y 11 les brindan a los usuarios más control sobre el acceso de las apps a las ubicaciones de sus dispositivos.
Cuando una app que se ejecuta en Android 11 solicita acceso a la ubicación, los usuarios tienen cuatro opciones:
- Permitir todo el tiempo
- Permitir solo con la app en uso (en Android 10)
- Solo una vez (en Android 11)
- Rechazar
Android 10

Android 11

En este codelab, aprenderás a recibir actualizaciones de la ubicación y a admitir la ubicación en cualquier versión de Android, en particular Android 10 y 11. Al final del codelab, tendrás una app que sigue las prácticas recomendadas actuales para recuperar actualizaciones de ubicación.
Requisitos previos
- Conocimiento del desarrollo de Android
- Conocimientos básicos sobre actividades, servicios y permisos
Actividades
- Sigue las prácticas recomendadas para la ubicación en Android.
- Controla los permisos de ubicación en primer plano (cuando el usuario solicita que tu app acceda a la ubicación del dispositivo mientras la usa).
- Modifica una app existente para agregar compatibilidad con la solicitud de acceso a la ubicación. Para ello, agrega código para suscribirse a la ubicación y cancelar la suscripción.
- Agrega compatibilidad con Android 10 y 11 a la app agregando lógica para acceder a la ubicación en primer plano o mientras se usa.
Requisitos
- Android Studio 3.4 o una versión posterior para ejecutar el código
- Un dispositivo o emulador que ejecute una versión preliminar para desarrolladores de Android 10 y 11
2. Comenzar
Clona el repositorio del proyecto inicial
Para que comiences lo antes posible, puedes crear tu proyecto a partir de este proyecto inicial. Si tienes Git instalado, simplemente puedes ejecutar el siguiente comando:
git clone https://github.com/android/codelab-while-in-use-location
Puedes visitar la página de GitHub directamente.
Si no tienes Git, puedes obtener el proyecto como un archivo ZIP:
Importa el proyecto
Abre Android Studio, selecciona "Open an existing Android Studio project" en la pantalla de bienvenida y abre el directorio del proyecto.
Después de que se cargue el proyecto, es posible que aparezca una alerta que indique que Git no está realizando un seguimiento de todos los cambios locales. Puedes hacer clic en Ignorar. (No enviarás ningún cambio al repositorio de Git).
En la esquina superior izquierda de la ventana del proyecto, deberías ver una imagen similar a la que se muestra más abajo si estás en la vista Android. (Si estás en la vista Project, deberás expandir el proyecto para ver lo mismo).

Hay dos carpetas (base y complete). Cada una se conoce como "módulo".
Ten en cuenta que Android Studio puede tardar varios segundos la primera vez que compile el proyecto en segundo plano. Durante este período, verás el siguiente mensaje en la barra de estado, en la parte inferior de Android Studio:

Espera a que Android Studio termine de indexar y compilar el proyecto antes de realizar cambios en el código. De esa manera, Android Studio podrá extraer todos los componentes necesarios.
Si recibes el mensaje Reload for language changes to take effect? o uno similar, selecciona Yes.
Comprende el proyecto inicial
Ya configuraste todo y puedes solicitar la ubicación en la app. Usa el módulo base como punto de partida. Durante cada paso, agrega código al módulo base. Cuando termines este codelab, el código del módulo base debe coincidir con el contenido del módulo complete. El módulo complete se puede usar para verificar tu trabajo o para usarlo como referencia si encuentras algún problema.
Los componentes clave incluyen los siguientes:
MainActivity: Es la IU para que el usuario permita que la app acceda a la ubicación del dispositivo.LocationService: Servicio que se suscribe a los cambios de ubicación y se da de baja de ellos, y se promueve a sí mismo como un servicio en primer plano (con una notificación) si el usuario sale de la actividad de la app. Aquí se agrega el código de ubicación.Util: Agrega funciones de extensión para la claseLocationy guarda la ubicación enSharedPreferences(capa de datos simplificada).
Configuración del emulador
Para obtener información sobre cómo configurar un emulador de Android, consulta Cómo ejecutar en un emulador.
Ejecuta el proyecto inicial
Ejecuta tu app.
- Conecta tu dispositivo Android a la computadora o inicia un emulador. (Asegúrate de que el dispositivo ejecute Android 10 o una versión posterior).
- En la barra de herramientas, selecciona la configuración
baseen el selector desplegable y haz clic en Run:

- Observa que la siguiente app aparece en tu dispositivo:

Es posible que observes que no aparece información de ubicación en la pantalla de salida. Esto se debe a que aún no agregaste el código de ubicación.
3. Cómo agregar la ubicación
Conceptos
El objetivo de este codelab es mostrarte cómo recibir actualizaciones de ubicación y, finalmente, admitir Android 10 y Android 11.
Sin embargo, antes de comenzar a codificar, es conveniente revisar los conceptos básicos.
Tipos de acceso a la ubicación
Es posible que recuerdes las cuatro opciones diferentes para el acceso a la ubicación del comienzo del codelab. A continuación, se explica qué significan:
- Permitir solo con la app en uso
- Esta opción es la recomendada para la mayoría de las apps. También conocida como acceso "mientras está en uso" o "solo en primer plano", esta opción se agregó en Android 10 y permite a los desarrolladores recuperar la ubicación solo mientras se usa la app de forma activa. Se considera que una app está activa si se cumple alguna de las siguientes condiciones:
- Se muestra una actividad.
- Se está ejecutando un servicio en primer plano con una notificación continua.
- Solo una vez
- Esta opción, que se agregó en Android 11, es igual a Permitir solo con la app en uso, pero por un período limitado. Para obtener más información, consulta Permisos de un solo uso.
- Denegar
- Esta opción impide el acceso a la información de ubicación.
- Permitir todo el tiempo
- Esta opción permite el acceso a la ubicación en todo momento, pero requiere un permiso adicional para Android 10 y versiones posteriores. También debes asegurarte de tener un caso de uso válido y satisfacer las políticas de ubicación. No verás esta opción en este codelab, ya que es un caso de uso menos frecuente. Sin embargo, si tienes un caso de uso válido y quieres comprender cómo controlar correctamente la ubicación todo el tiempo, incluido el acceso a la ubicación en segundo plano, consulta el ejemplo de LocationUpdatesBackgroundKotlin.
Servicios, servicios en primer plano y vinculación
Para admitir por completo las actualizaciones de ubicación de Permitir solo con la app en uso, debes tener en cuenta cuándo el usuario sale de tu app. Si deseas seguir recibiendo actualizaciones en esa situación, debes crear un Service en primer plano y asociarlo con un Notification.
Además, si quieres usar el mismo Service para solicitar actualizaciones de ubicación cuando tu app está visible y cuando el usuario sale de ella, debes vincular o desvincular ese Service al elemento de IU.
Dado que este codelab se enfoca solo en obtener actualizaciones de la ubicación, puedes encontrar todo el código que necesitas en la clase ForegroundOnlyLocationService.kt. Puedes explorar esa clase y el MainActivity.kt para ver cómo funcionan en conjunto.
Para obtener más información, consulta Descripción general de los servicios y Descripción general de los servicios vinculados.
Permisos
Para recibir actualizaciones de ubicación de un NETWORK_PROVIDER o un GPS_PROVIDER, debes solicitar el permiso del usuario declarando el permiso ACCESS_COARSE_LOCATION o ACCESS_FINE_LOCATION, respectivamente, en el archivo de manifiesto de Android. Sin estos permisos, tu app no podrá solicitar acceso a la ubicación durante el tiempo de ejecución.
Esos permisos abarcan los casos de Solo una vez y Permitir solo con la app en uso cuando tu app se usa en un dispositivo que ejecuta Android 10 o versiones posteriores.
Ubicación
Tu app puede acceder al conjunto de servicios de ubicación compatibles a través de las clases del paquete com.google.android.gms.location.
Consulta las clases principales:
FusedLocationProviderClient- Este es el componente central del framework de ubicación. Una vez creado, lo usas para solicitar actualizaciones de ubicación y obtener la última ubicación conocida.
LocationRequest- Es un objeto de datos que contiene parámetros de calidad del servicio para las solicitudes (intervalos de actualizaciones, prioridades y precisión). Este valor se pasa a
FusedLocationProviderClientcuando solicitas actualizaciones de ubicación. LocationCallback- Se usa para recibir notificaciones cuando cambia la ubicación del dispositivo o ya no se puede determinar. Se pasa un
LocationResulten el que puedes obtener elLocationpara guardarlo en tu base de datos.
Ahora que tienes una idea básica de lo que harás, ¡comienza con el código!
4. Cómo agregar funciones de ubicación
Este codelab se enfoca en la opción de ubicación más común: Permitir solo con la app en uso.
Para recibir actualizaciones de ubicación, tu app debe tener una actividad visible o un servicio que se ejecute en primer plano (con una notificación).
Permisos
El objetivo de este codelab es mostrar cómo recibir actualizaciones de ubicación, no cómo solicitar permisos de ubicación, por lo que el código basado en permisos ya está escrito para ti. Puedes omitirlo si ya lo entiendes.
A continuación, se destacan los permisos (no se requiere ninguna acción para esta parte):
- Declara qué permiso usas en el
AndroidManifest.xml. - Antes de intentar acceder a la información de ubicación, verifica si el usuario le otorgó permiso a tu app para hacerlo. Si tu app aún no recibió el permiso, solicítalo.
- Controla la elección de permisos del usuario. (Puedes ver este código en
MainActivity.kt).
Si buscas TODO: Step 1.0, Review Permissions en AndroidManifest.xml o MainActivity.kt, verás todo el código escrito para los permisos.
Para obtener más información, consulta la Descripción general de los permisos.
Ahora, comienza a escribir código de ubicación.
Revisa las variables clave necesarias para las actualizaciones de ubicación
En el módulo base, busca TODO: Step 1.1, Review variables en el
Archivo ForegroundOnlyLocationService.kt.
No es necesario realizar ninguna acción en este paso. Solo debes revisar el siguiente bloque de código, junto con los comentarios, para comprender las clases y variables clave que usas para recibir actualizaciones de la ubicación.
// TODO: Step 1.1, Review variables (no changes).
// FusedLocationProviderClient - Main class for receiving location updates.
private lateinit var fusedLocationProviderClient: FusedLocationProviderClient
// LocationRequest - Requirements for the location updates, i.e., how often you
// should receive updates, the priority, etc.
private lateinit var locationRequest: LocationRequest
// LocationCallback - Called when FusedLocationProviderClient has a new Location.
private lateinit var locationCallback: LocationCallback
// Used only for local storage of the last known location. Usually, this would be saved to your
// database, but because this is a simplified sample without a full database, we only need the
// last location to create a Notification if the user navigates away from the app.
private var currentLocation: Location? = null
Revisa la inicialización de FusedLocationProviderClient
En el módulo base, busca TODO: Step 1.2, Review the FusedLocationProviderClient en el archivo ForegroundOnlyLocationService.kt. El código debería ser similar al siguiente:
// TODO: Step 1.2, Review the FusedLocationProviderClient.
fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(this)
Como se mencionó en los comentarios anteriores, esta es la clase principal para obtener actualizaciones de la ubicación. La variable ya está inicializada, pero es importante que revises el código para comprender cómo se inicializa. Más adelante, agregarás código aquí para solicitar actualizaciones de la ubicación.
Inicializa el objeto LocationRequest
- En el módulo
base, buscaTODO: Step 1.3, Create a LocationRequesten el archivoForegroundOnlyLocationService.kt. - Agrega el siguiente código después del comentario.
El código de inicialización de LocationRequest agrega los parámetros adicionales de calidad del servicio que necesitas para tu solicitud (intervalos, tiempo de espera máximo y prioridad).
// TODO: Step 1.3, Create a LocationRequest.
locationRequest = LocationRequest.create().apply {
// Sets the desired interval for active location updates. This interval is inexact. You
// may not receive updates at all if no location sources are available, or you may
// receive them less frequently than requested. You may also receive updates more
// frequently than requested if other applications are requesting location at a more
// frequent interval.
//
// IMPORTANT NOTE: Apps running on Android 8.0 and higher devices (regardless of
// targetSdkVersion) may receive updates less frequently than this interval when the app
// is no longer in the foreground.
interval = TimeUnit.SECONDS.toMillis(60)
// Sets the fastest rate for active location updates. This interval is exact, and your
// application will never receive updates more frequently than this value.
fastestInterval = TimeUnit.SECONDS.toMillis(30)
// Sets the maximum time when batched location updates are delivered. Updates may be
// delivered sooner than this interval.
maxWaitTime = TimeUnit.MINUTES.toMillis(2)
priority = LocationRequest.PRIORITY_HIGH_ACCURACY
}
- Lee los comentarios para comprender cómo funciona cada uno.
Inicializa el LocationCallback
- En el módulo
base, buscaTODO: Step 1.4, Initialize the LocationCallbacken el archivoForegroundOnlyLocationService.kt. - Agrega el siguiente código después del comentario.
// TODO: Step 1.4, Initialize the LocationCallback.
locationCallback = object : LocationCallback() {
override fun onLocationResult(locationResult: LocationResult) {
super.onLocationResult(locationResult)
// Normally, you want to save a new location to a database. We are simplifying
// things a bit and just saving it as a local variable, as we only need it again
// if a Notification is created (when the user navigates away from app).
currentLocation = locationResult.lastLocation
// Notify our Activity that a new location was added. Again, if this was a
// production app, the Activity would be listening for changes to a database
// with new locations, but we are simplifying things a bit to focus on just
// learning the location side of things.
val intent = Intent(ACTION_FOREGROUND_ONLY_LOCATION_BROADCAST)
intent.putExtra(EXTRA_LOCATION, currentLocation)
LocalBroadcastManager.getInstance(applicationContext).sendBroadcast(intent)
// Updates notification content if this service is running as a foreground
// service.
if (serviceRunningInForeground) {
notificationManager.notify(
NOTIFICATION_ID,
generateNotification(currentLocation))
}
}
}
El LocationCallback que creas aquí es la devolución de llamada que FusedLocationProviderClient llamará cuando haya disponible una nueva actualización de ubicación.
En tu devolución de llamada, primero obtienes la ubicación más reciente con un objeto LocationResult. Después de eso, le notificas a tu Activity la nueva ubicación a través de una transmisión local (si está activa) o actualizas el Notification si este servicio se ejecuta como un Service en primer plano.
- Lee los comentarios para comprender qué hace cada parte.
Cómo suscribirse a los cambios de ubicación
Ahora que inicializaste todo, debes indicarle a FusedLocationProviderClient que quieres recibir actualizaciones.
- En el módulo
base, buscaStep 1.5, Subscribe to location changesen el archivoForegroundOnlyLocationService.kt. - Agrega el siguiente código después del comentario.
// TODO: Step 1.5, Subscribe to location changes.
fusedLocationProviderClient.requestLocationUpdates(locationRequest, locationCallback, Looper.getMainLooper())
La llamada a requestLocationUpdates() le permite al FusedLocationProviderClient saber que deseas recibir actualizaciones de ubicación.
Probablemente reconozcas el LocationRequest y el LocationCallback que definiste antes. Estos permiten que FusedLocationProviderClient conozca los parámetros de calidad del servicio para tu solicitud y a qué debe llamar cuando tenga una actualización. Por último, el objeto Looper especifica el subproceso para la devolución de llamada.
También puedes notar que este código se encuentra dentro de una instrucción try/catch. Este método requiere un bloque de este tipo porque se produce un SecurityException cuando tu app no tiene permiso para acceder a la información sobre la ubicación.
Cómo anular la suscripción a los cambios de ubicación
Cuando la app ya no necesita acceder a la información de la ubicación, es importante cancelar la suscripción a las actualizaciones de ubicación.
- En el módulo
base, buscaTODO: Step 1.6, Unsubscribe to location changesen el archivoForegroundOnlyLocationService.kt. - Agrega el siguiente código después del comentario.
// TODO: Step 1.6, Unsubscribe to location changes.
val removeTask = fusedLocationProviderClient.removeLocationUpdates(locationCallback)
removeTask.addOnCompleteListener { task ->
if (task.isSuccessful) {
Log.d(TAG, "Location Callback removed.")
stopSelf()
} else {
Log.d(TAG, "Failed to remove Location Callback.")
}
}
El método removeLocationUpdates() configura una tarea para que el FusedLocationProviderClient sepa que ya no quieres recibir actualizaciones de ubicación para tu LocationCallback. El addOnCompleteListener() proporciona la devolución de llamada para la finalización y ejecuta el Task.
Al igual que en el paso anterior, tal vez hayas notado que este código se encuentra dentro de una instrucción try/catch. Este método requiere un bloque de este tipo porque se produce un SecurityException cuando tu app no tiene permiso para acceder a la información sobre la ubicación.
Es posible que te preguntes cuándo se llaman los métodos que contienen el código de suscripción o cancelación de la suscripción. Se activan en la clase principal cuando el usuario presiona el botón. Si quieres verlo, consulta la clase MainActivity.kt.
Ejecutar la app
Ejecuta tu app desde Android Studio y prueba el botón de ubicación.
Deberías ver la información de ubicación en la pantalla de resultados. Esta es una app completamente funcional para Android 9.


5. Compatibilidad con Android 10
En esta sección, agregarás compatibilidad con Android 10.
Tu app ya se suscribe a los cambios de ubicación, por lo que no hay mucho trabajo por hacer.
De hecho, todo lo que tienes que hacer es especificar que tu servicio en primer plano se usa para fines de ubicación.
SDK de destino 29
- En el módulo
base, buscaTODO: Step 2.1, Target Android 10 and then Android 11.en el archivobuild.gradle. - Realiza los siguientes cambios:
- Establece
targetSdkVersionen29.
El código debería ser similar al siguiente:
android {
// TODO: Step 2.1, Target Android 10 and then Android 11.
compileSdkVersion 29
defaultConfig {
applicationId "com.example.android.whileinuselocation"
minSdkVersion 26
targetSdkVersion 29
versionCode 1
versionName "1.0"
}
...
}
Después de hacerlo, se te pedirá que sincronices tu proyecto. Haz clic en Sincronizar ahora.

Después de eso, tu app estará casi lista para Android 10.
Agregar tipo de servicio en primer plano
En Android 10, debes incluir el tipo de servicio en primer plano si necesitas acceso a la ubicación durante el uso. En tu caso, se usa para obtener información de ubicación.
En el módulo base, busca TODO: 2.2, Add foreground service type en AndroidManifest.xml y agrega el siguiente código al elemento <service>:
android:foregroundServiceType="location"
El código debería ser similar al siguiente:
<application>
...
<!-- Foreground services in Android 10+ require type. -->
<!-- TODO: 2.2, Add foreground service type. -->
<service
android:name="com.example.android.whileinuselocation.ForegroundOnlyLocationService"
android:enabled="true"
android:exported="false"
android:foregroundServiceType="location" />
</application>
Eso es todo. Tu app admite la ubicación en Android 10 para el uso "en primer plano" siguiendo las prácticas recomendadas para la ubicación en Android.
Ejecutar la app
Ejecuta tu app desde Android Studio y prueba el botón de ubicación.
Todo debería funcionar como antes, pero ahora en Android 10. Si no aceptaste los permisos de ubicación antes, ahora deberías ver la pantalla de permisos.



6. Compatibilidad con Android 11
En esta sección, segmentarás tu app para Android 11.
¡Buenas noticias! No es necesario que cambies ningún archivo, excepto el archivo build.gradle.
SDK de destino 11
- En el módulo
base, buscaTODO: Step 2.1, Target SDKen el archivobuild.gradle. - Realiza los siguientes cambios:
- De
compileSdkVersiona30 - De
targetSdkVersiona30
El código debería ser similar al siguiente:
android {
TODO: Step 2.1, Target Android 10 and then Android 11.
compileSdkVersion 30
defaultConfig {
applicationId "com.example.android.whileinuselocation"
minSdkVersion 26
targetSdkVersion 30
versionCode 1
versionName "1.0"
}
...
}
Después de hacerlo, se te pedirá que sincronices tu proyecto. Haz clic en Sincronizar ahora.

Después de eso, tu app estará lista para Android 11.
Ejecutar la app
Ejecuta tu app desde Android Studio y haz clic en el botón.
Todo debería funcionar como antes, pero ahora en Android 11. Si no aceptaste los permisos de ubicación antes, ahora deberías ver la pantalla de permisos.


7. Estrategias de ubicación para Android
Al verificar y solicitar permisos de ubicación como se indica en este codelab, tu app puede llevar un registro de su nivel de acceso con respecto a la ubicación del dispositivo.
En esta página, se enumeran algunas prácticas recomendadas clave relacionadas con los permisos de ubicación. Para obtener más información sobre cómo proteger los datos de los usuarios, consulta las prácticas recomendadas sobre permisos de la app.
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 segmenta para Android 10 o versiones posteriores y tiene un servicio en primer plano, declara un
foregroundServiceTypede"location"en el manifiesto. - No solicites permisos de ubicación en segundo plano, a menos que tengas un caso de uso válido, como se describe en Acceso más seguro y transparente a la ubicación del usuario.
Admite la degradación elegante si no se otorga 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.
8. Felicitaciones
Aprendiste a recibir actualizaciones de ubicación en Android teniendo en cuenta las prácticas recomendadas.
Más información
- Muestra completa para usar la ubicación en segundo plano si tienes un caso de uso válido
- Cómo solicitar actualizaciones de ubicación