Saltar al contenido
Todas las entradas

Health Connect en Android en 2026: leer y escribir datos sin renunciar al local-first

Una guía práctica sobre la API Health Connect de Android en 2026 — permisos, lecturas en segundo plano y por qué las apps local-first deberían tratarla como opcional, no como fuente de verdad.

MFKAPPS 5 min de lectura

Health Connect es el almacén en el dispositivo del que Android ahora espera que las apps de salud y fitness lean y escriban, en lugar de mantener su propio silo. Para una app local-first, esto plantea una pregunta honesta: ¿es un lugar donde publicar datos, un lugar de donde leerlos, o ambos — y decir que sí a cualquiera de las dos opciones desplaza silenciosamente tu fuente de verdad fuera del dispositivo en el que prometiste mantenerla? Esto es lo que la API realmente te pide, y el límite que yo trazo alrededor de ella.

Qué es Health Connect, y qué no es

Health Connect es un almacén de datos a nivel de sistema, no un servicio en la nube. Los registros — pasos, hidratación, peso, sesiones de sueño — viven en una base de datos local cuyo acceso media Android, y cualquier app que el usuario apruebe puede leer o escribir a través de ella. Ahí está el atractivo: una app de hidratación y una app de fitness pueden compartir un único total de hidratación en lugar de mantener cada una un recuento separado e incompleto. También ahí está el riesgo. En el momento en que tu app escribe ahí, cualquier otra app a la que el usuario haya concedido acceso de lectura puede ver esos datos también. Local-first no deja de significar nada en cuanto tocas Health Connect, pero sí pasa a significar algo más estrecho: los datos siguen sin salir nunca del dispositivo, pero ya no son visibles solo para ti.

En teléfonos sin la app de Health Connect preinstalada, la librería cliente propone una instalación desde Play la primera vez que la solicitas. Presupuesta esa ruta de fallo — un dispositivo nuevo o una ROM recortada pueden dejar la API no disponible, y tu solicitud de permiso necesita un fallback real, no un cierre inesperado.

El modelo de permisos de 2026

Los permisos de salud no son permisos en tiempo de ejecución en el sentido de ActivityCompat.requestPermissions — pasan por una pantalla de justificación dedicada que gestiona la propia app de Health Connect, no el diálogo de tu app. Declaras la intención en el manifiesto y luego lanzas un contrato:

val requestPermissions = registerForActivityResult(
    PermissionController.createRequestPermissionResultContract()
) { granted ->
    if (HealthPermission.getWritePermission(HydrationRecord::class) in granted) {
        // proceed
    }
}

requestPermissions.launch(
    setOf(
        HealthPermission.getWritePermission(HydrationRecord::class),
        HealthPermission.getReadPermission(HydrationRecord::class),
    )
)

El conjunto de resultado solo te dice qué se concedió, nunca por qué se denegó algo — no hay bandera de “denegado para siempre”, no hay justificación que puedas inspeccionar. Si un permiso que esperabas no está en el conjunto devuelto, lo correcto es comprobar PermissionController.getGrantedPermissions() antes de cada lectura o escritura y degradar con elegancia, no asumir que la concesión de ayer sigue siendo válida. Los usuarios pueden revocar los permisos de Health Connect desde los ajustes del sistema en cualquier momento, completamente fuera del ciclo de vida de tu app, y tu siguiente llamada a la API simplemente fallará como si nunca se hubiera concedido.

Escribir y leer un registro

Un HydrationRecord es un valor con un rango de tiempo y un volumen, ligado a los propios metadatos de la app que escribe:

val record = HydrationRecord(
    startTime = Instant.now(),
    startZoneOffset = ZoneOffset.systemDefault().rules.getOffset(Instant.now()),
    endTime = Instant.now(),
    endZoneOffset = ZoneOffset.systemDefault().rules.getOffset(Instant.now()),
    volume = Volume.milliliters(250.0),
)

healthConnectClient.insertRecords(listOf(record))

Leer de vuelta es una consulta por rango de tiempo, no un escaneo de tabla completa — se espera que pidas una ventana, no “todo”:

val response = healthConnectClient.readRecords(
    ReadRecordsRequest(
        recordType = HydrationRecord::class,
        timeRangeFilter = TimeRangeFilter.between(
            startOfToday, Instant.now()
        ),
    )
)

Cada registro lleva un metadata.dataOrigin, así que puedes distinguir tus propias escrituras de las de un pulsómetro o las de otra app — útil en el momento en que estás agregando un “total de hoy” a partir de más de una fuente y no quieres contar dos veces.

Las lecturas en segundo plano necesitan un permiso aparte

Leer datos de Health Connect mientras tu app no está en primer plano requiere PERMISSION_READ_HEALTH_DATA_IN_BACKGROUND además del permiso por tipo de registro, y Android lo trata como lo bastante sensible como para merecer su propia línea en la pantalla de justificación. Si tu caso de uso es “sincronizar una vez cuando se abre la app”, pásalo por alto — pídelo solo para un trabajo en segundo plano real, como un widget o una notificación de resumen diario que tiene que calcular su cifra sin que el usuario abra antes la app. Pedirlo cuando no lo necesitas no falla técnicamente; simplemente hace tu pantalla de permisos más larga y más alarmante de lo que la función justifica, que es justo el tipo de cosa que acaba costándote la concesión entera.

Por qué lo trato como un dato opcional y aditivo

Para algo como Hydrame, Health Connect resulta tentador por una razón: un usuario que también registra entrenamientos en otro sitio obtiene una única cifra de hidratación verdadera en lugar de dos que no coinciden. Pero también resulta tentador por la razón equivocada — es fácil dejar que “sincronizar con Health Connect” se convierta silenciosamente en “Health Connect es ahora la fuente de verdad”, momento en el que la propia base de datos local de la app se transforma en una caché que puede desviarse, y la promesa de que nada sale del dispositivo se vuelve más difusa cada vez que se concede acceso de lectura a otra app. La versión que de verdad publicaría trata Health Connect como una publicación de un solo sentido del mismo registro local, nunca como una vía de lectura de la que la app dependa para funcionar — desinstala la app de Health Connect por completo y la experiencia principal no debería notarlo.

La lista de comprobación

Antes de integrar Health Connect: comprueba la disponibilidad y gestiona el caso de la app ausente, solicita solo los permisos de registro específicos que usas, vuelve a comprobar los permisos concedidos antes de cada acceso en lugar de guardar en caché un sí de hace tres pantallas, limita las lecturas en segundo plano a trabajo en segundo plano real, y decide de antemano si estás publicando en Health Connect o dependiendo de ella — porque la API te dejará hacer cualquiera de las dos con gusto, y solo una de ellas mantiene honesta a una app local-first sobre dónde viven realmente sus datos.