Desde hace varias versiones, Android separa el permiso de ubicación en dos niveles independientes: aproximada y precisa. El usuario puede conceder solo la aproximada aunque la app haya pedido también la precisa, y puede cambiar esa elección en cualquier momento desde los ajustes del sistema. Diseñar Caladero me obligó a pensar, funcionalidad por funcionalidad, cuál de las dos hace falta realmente en cada caso, en vez de pedir la más precisa por defecto porque "por si acaso viene bien".
La diferencia técnica entre ambos niveles
ACCESS_COARSE_LOCATION da acceso a una ubicación con una precisión aproximada, típicamente del orden de varios cientos de metros a un par de kilómetros, suficiente para saber en qué zona general está el dispositivo. ACCESS_FINE_LOCATION da acceso a la ubicación más precisa disponible, normalmente basada en GPS, con un margen de error que puede bajar a pocos metros en condiciones favorables.
Desde Android 12, un usuario puede conceder el permiso de ubicación pero elegir explícitamente que solo sea la versión aproximada, aunque la app haya solicitado la precisa en el manifiesto. Esto significa que, como desarrollador, no puedo asumir que si tengo declarado ACCESS_FINE_LOCATION voy a recibir siempre datos precisos: tengo que comprobar en tiempo de ejecución qué nivel concedió realmente el usuario y diseñar la funcionalidad para que degrade con sensatez si solo se concedió la versión aproximada.
Cómo decido cuál pedir, funcionalidad por funcionalidad
Mi criterio no es "qué es lo más preciso posible" sino "qué es lo mínimo que la funcionalidad necesita para cumplir su propósito". Repaso las pantallas de Caladero con esta pregunta en mente:
Centrar el mapa en la zona del usuario al abrir la app. Esto solo necesita saber en qué área general está el usuario para no mostrar, por ejemplo, un mapa centrado en otro continente. La ubicación aproximada es suficiente para este caso; pedir precisión de metros para simplemente centrar una vista de mapa a escala de ciudad sería pedir más de lo necesario.
Guardar un punto de pesca en la ubicación exacta del usuario. Aquí sí hace falta precisión real, porque el valor de la funcionalidad depende directamente de que el punto guardado corresponda al lugar exacto donde el usuario está pescando, no a una zona aproximada de varios cientos de metros que podría corresponder a la orilla equivocada de un embalse. En este caso pido explícitamente ubicación precisa.
Mostrar puntos guardados cercanos en un listado. Para ordenar una lista de puntos guardados por cercanía aproximada al usuario, la ubicación aproximada vuelve a ser suficiente; no hace falta el nivel de detalle de GPS para simplemente ordenar una lista.
Cómo se solicita cada nivel en código
Cuando una funcionalidad concreta solo necesita precisión aproximada, solicito exclusivamente ese permiso:
requestPermissionLauncher.launch(Manifest.permission.ACCESS_COARSE_LOCATION)
Cuando una funcionalidad necesita precisión real, como guardar un punto exacto, solicito ambos permisos juntos, ya que la práctica recomendada de Android es pedir siempre ACCESS_COARSE_LOCATION junto con ACCESS_FINE_LOCATION, dejando que sea el propio usuario quien decida en el diálogo del sistema si concede el nivel preciso o se queda con el aproximado:
requestPermissionLauncher.launch(
arrayOf(
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION
)
)
Después, compruebo qué concedió realmente el usuario, porque el resultado puede ser cualquiera de las dos, o ninguna:
val fineGranted = permisos[Manifest.permission.ACCESS_FINE_LOCATION] == true
val coarseGranted = permisos[Manifest.permission.ACCESS_COARSE_LOCATION] == true
when {
fineGranted -> activarModoPrecision()
coarseGranted -> activarModoAproximado()
else -> mostrarMensajeSinUbicacion()
}
Qué pasa si el usuario solo concede aproximada para guardar un punto exacto
Este es el caso donde más se nota la diferencia entre los dos niveles, y donde tengo que ser explícito con el usuario. Si intenta guardar un punto exacto de pesca pero solo ha concedido ubicación aproximada, Caladero no simula una falsa precisión: muestra un aviso explicando que, para guardar un punto con la precisión necesaria, hace falta conceder ubicación precisa, con un enlace directo a los ajustes de permisos de la app. No creo que sea buena práctica guardar un punto con una precisión de varios cientos de metros y presentarlo como si fuera exacto, porque eso rompería la utilidad real de la funcionalidad sin que el usuario lo supiera.
Errores y matices que he encontrado
Uno de los errores que cometí al principio fue asumir que, si el usuario había concedido el permiso preciso una vez, ese estado no cambiaría nunca. En realidad, el usuario puede revocar o cambiar el nivel de precisión concedido en cualquier momento desde los ajustes del sistema, incluso con la app instalada y sin que la app reciba ninguna notificación directa de ese cambio salvo cuando vuelve a comprobar el permiso. Por eso ahora compruebo el nivel de permiso vigente cada vez que se ejecuta una acción que depende de la ubicación, no solo una vez al arrancar la app.
Otro matiz importante: la disponibilidad de una lectura de ubicación aproximada o precisa también depende de las condiciones reales del entorno, no solo del permiso concedido. En interiores o en zonas con mala cobertura, incluso con permiso de ubicación precisa concedido, el sistema puede tardar más en obtener una lectura fiable o directamente no conseguirla. El permiso concedido es una condición necesaria, pero no es garantía de que la lectura llegue rápido ni con la precisión esperada en todas las circunstancias.
Conclusión
Pedir ubicación aproximada o precisa no debería decidirse por comodidad de desarrollo, sino funcionalidad por funcionalidad, según lo que cada pantalla concreta necesita de verdad para cumplir su propósito. En Caladero esto significa que la mayoría de pantallas funcionan perfectamente con ubicación aproximada, y solo la función central de guardar un punto de pesca exacto pide y necesita precisión real. Ese ajuste fino no solo respeta mejor la privacidad del usuario, también hace que los diálogos de permiso que sí aparecen tengan un motivo evidente, lo cual, como comento en el artículo sobre permisos Android: pedir solo lo necesario, es lo que más influye en que el usuario acabe concediendo el permiso cuando de verdad hace falta.
