Health Connect sur Android en 2026 : lire et écrire des données sans renoncer au local-first
Un guide pratique de l'API Health Connect d'Android en 2026 — permissions, lectures en arrière-plan, et pourquoi une app local-first devrait la traiter comme optionnelle, pas comme une vérité absolue.
Health Connect est le magasin de données sur l’appareil vers lequel Android attend désormais que les apps santé et fitness lisent et écrivent, plutôt que de garder chacune son propre silo. Pour une app local-first, cela pose une question honnête : est-ce un endroit où publier des données, un endroit où les lire, ou les deux — et est-ce que dire oui à l’un ou l’autre déplace discrètement votre source de vérité hors de l’appareil que vous aviez promis de respecter. Voici ce que l’API demande réellement, et la limite que je trace autour d’elle.
Ce qu’est Health Connect, et ce qu’il n’est pas
Health Connect est un magasin de données au niveau du système, pas un service cloud. Les enregistrements — pas, hydratation, poids, sessions de sommeil — vivent dans une base de données locale dont Android arbitre l’accès, et toute app que l’utilisateur approuve peut y lire ou y écrire. C’est tout l’intérêt : une app d’hydratation et une app de fitness peuvent partager un même total d’hydratation au lieu de tenir chacune un compte séparé et incomplet. C’est aussi le risque. Dès que votre app y écrit, n’importe quelle autre app à qui l’utilisateur a accordé un accès en lecture peut voir cette donnée aussi. Le local-first ne perd pas tout son sens dès qu’on touche à Health Connect, mais il en prend un sens plus étroit : la donnée ne quitte toujours jamais l’appareil, mais elle n’est plus visible de vous seul.
Sur les téléphones où l’app Health Connect n’est pas préinstallée, la bibliothèque cliente propose une installation depuis le Play Store dès la première requête. Prévoyez ce chemin d’échec — un appareil neuf ou une ROM allégée peut rendre l’API indisponible, et votre demande de permission a besoin d’un vrai repli, pas d’un crash.
Le modèle de permissions en 2026
Les permissions santé ne sont pas des permissions à l’exécution au sens de ActivityCompat.requestPermissions — elles passent par un écran de justification dédié que possède l’app Health Connect, pas votre propre boîte de dialogue. Vous déclarez l’intention dans le manifeste, puis vous lancez un contrat :
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),
)
)
L’ensemble de résultats vous dit seulement ce qui a été accordé, jamais pourquoi quelque chose a été refusé — pas de drapeau « refusé définitivement », pas de justification que vous puissiez inspecter. Si une permission que vous attendiez n’est pas dans l’ensemble retourné, le bon réflexe est de vérifier PermissionController.getGrantedPermissions() avant chaque lecture ou écriture et de dégrader proprement, pas de supposer que l’octroi d’hier tient toujours. Les utilisateurs peuvent révoquer les permissions Health Connect depuis les réglages système à tout moment, entièrement en dehors du cycle de vie de votre app, et votre prochain appel API échouera simplement comme s’il n’avait jamais été accordé.
Écrire et lire un enregistrement
Un HydrationRecord est une valeur avec une plage horaire et un volume, liée aux métadonnées propres de l’app qui écrit :
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))
Relire est une requête sur une plage temporelle, pas un balayage complet de table — on attend de vous que vous demandiez une fenêtre, pas « tout » :
val response = healthConnectClient.readRecords(
ReadRecordsRequest(
recordType = HydrationRecord::class,
timeRangeFilter = TimeRangeFilter.between(
startOfToday, Instant.now()
),
)
)
Chaque enregistrement porte un metadata.dataOrigin, ce qui permet de distinguer vos propres écritures de celles d’un tracker fitness ou d’une autre app — utile dès que vous agrégez un « total du jour » à partir de plusieurs sources et que vous ne voulez pas compter en double.
Les lectures en arrière-plan demandent une permission séparée
Lire des données Health Connect pendant que votre app n’est pas au premier plan exige PERMISSION_READ_HEALTH_DATA_IN_BACKGROUND en plus de la permission par type d’enregistrement, et Android la traite comme suffisamment sensible pour lui réserver sa propre ligne dans l’écran de justification. Si votre cas d’usage est « synchroniser une fois à l’ouverture de l’app », passez-la — ne la demandez que pour une vraie tâche en arrière-plan, comme un widget ou une notification de récapitulatif quotidien qui doit calculer son chiffre sans que l’utilisateur ait d’abord ouvert l’app. La demander sans en avoir besoin ne provoque pas d’échec technique ; cela rend simplement votre écran de permissions plus long et plus alarmant que la fonctionnalité ne le justifie — le genre de chose qui finit par vous coûter l’octroi tout entier.
Pourquoi je le traite comme une donnée optionnelle, additive
Pour une app comme Hydrame, Health Connect est tentant pour une raison précise : un utilisateur qui note aussi ses séances de sport ailleurs obtient un seul chiffre d’hydratation fiable au lieu de deux qui se contredisent. Mais il est tentant pour une mauvaise raison aussi — il est facile de laisser « synchroniser vers Health Connect » devenir discrètement « Health Connect fait maintenant foi », moment où la base de données locale de l’app se transforme en cache susceptible de dériver, et où la promesse que rien ne quitte l’appareil devient un peu plus floue à chaque nouvelle app qui obtient un accès en lecture. La version que j’expédierais vraiment traite Health Connect comme une publication à sens unique du même enregistrement local, jamais comme un chemin de lecture dont l’app dépendrait pour fonctionner — désinstallez complètement l’app Health Connect, et l’expérience principale ne devrait rien remarquer.
La check-list
Avant de brancher Health Connect : vérifiez la disponibilité et gérez le cas où l’app manque, ne demandez que les permissions d’enregistrement précises que vous utilisez, revérifiez les permissions accordées avant chaque accès plutôt que de mettre en cache un oui obtenu trois écrans plus tôt, limitez les lectures en arrière-plan à du vrai travail en arrière-plan, et décidez à l’avance si vous publiez vers Health Connect ou si vous en dépendez — parce que l’API vous laissera volontiers faire l’un ou l’autre, et un seul des deux garde une app local-first honnête sur l’endroit où vivent réellement ses données.
// À lire aussi
D’autres notes du journal
L'authentification biométrique sur Android en 2026 : BiometricPrompt, le Keystore et le verrouillage d'une app local-first
Un guide pratique d'androidx.biometric sur Android — BiometricPrompt, clés adossées à un CryptoObject, repli sur les identifiants de l'appareil, et les erreurs qui font qu'une empreinte digitale ne protège rien.
L'API In-App Review d'Android : demander une note sans être pénible
Un guide pratique de l'API In-App Review de Google — comment elle fonctionne réellement, quand la déclencher, et pourquoi la popup classique « notez-nous » nuit discrètement à votre note sur le Play Store.
Raccourcis d'application et tuiles de Paramètres rapides sur Android : enregistrer de l'eau sans ouvrir l'application
Un guide pratique de l'API dynamique ShortcutManager et de TileService sur Android — comment permettre à une action en un tap de contourner complètement l'application, avec les pièges qui font trébucher la plupart des implémentations.