← Tous les articles

HealthKit dans iOS 27 : zones d'effort, nouveaux types

Depuis des années, HealthKit traitait les zones de fréquence cardiaque d’entraînement comme un citoyen officieux : chaque application de course ou de cyclisme qui affichait un graphique à cinq zones calculait ces zones elle-même, récupérait les relevés bruts de fréquence cardiaque sous forme de HKQuantitySample, les répartissait dans des seuils codés en dur ou saisis par l’utilisateur, puis additionnait à la main le temps passé dans chaque tranche. iOS 27 met fin à ce travail artisanal. Les zones deviennent un type HealthKit structuré que le système génère, que la personne peut modifier dans les réglages de Santé et que votre application relit avec le temps par zone déjà comptabilisé. La même version ajoute deux types de catégorie liés à la santé reproductive, menopausalState et bleedingAfterMenopause, qui comblent une lacune du modèle de suivi du cycle de HealthKit.1

Deux fils conducteurs traversent les ajouts d’iOS 27, et ils partagent une même forme. Le fil des zones d’entraînement prend un calcul que les applications devaient s’approprier et le déplace dans le framework, où la définition de zone d’une même personne reste cohérente d’une application à l’autre. Le fil des nouveaux types attribue un échantillon de catégorie typé à des étapes de vie que HealthKit ne pouvait jusqu’ici pas représenter. Les deux suivent la grammaire existante de HealthKit : des types de quantité pour les valeurs mesurées, des types de catégorie pour les événements et les états. Cet article parcourt chacun d’eux à la lumière de la documentation d’Apple, avec le cadrage habituel de la série : ce qu’une application qui embarque déjà HealthKit doit ajouter pour gagner chaque capacité.

En bref

  • HKWorkoutZoneConfiguration définit un ensemble complet de zones pour un type de quantité. Le système génère automatiquement les zones à partir des indicateurs de santé d’une personne, celle-ci peut les modifier dans les réglages de Santé, et une application peut fournir des zones personnalisées pour un entraînement donné.2
  • HKWorkoutZoneGroup associe une configuration de zones aux données de temps par zone. Vous le relisez depuis les instances d’entraînement terminé pour obtenir les durées par zone que le framework a déjà calculées, au lieu de répartir vous-même les échantillons de fréquence cardiaque.3
  • preferredWorkoutZoneConfiguration(for:), sur HKHealthStore, renvoie la configuration de zones préférée de la personne pour un type de quantité, afin que vos graphiques s’alignent sur les seuils qu’elle voit partout ailleurs.4
  • menopausalState, accompagné de l’énumération HKCategoryValueMenopausalState, enregistre l’état ménopausique à un instant précis ; la date de début et la date de fin de l’échantillon doivent être identiques, sans quoi l’enregistrement échoue.56
  • bleedingAfterMenopause enregistre les saignements post-ménopausiques sous forme d’intervalle assorti d’une valeur d’intensité, en les maintenant cliniquement distincts du flux menstruel.7

Les zones d’entraînement vous ont toujours incombé

Avant iOS 27, une application d’entraînement qui voulait afficher des zones de fréquence cardiaque faisait tout le travail. Elle interrogeait les données de fréquence cardiaque HKQuantitySample pour la plage horaire de l’entraînement, décidait de l’emplacement des frontières de zone (220 moins l’âge, pourcentages du seuil lactique, ou une valeur saisie par l’utilisateur dans un écran de réglages), parcourait les échantillons dans l’ordre et accumulait les secondes passées dans chaque bande. Chaque application choisissait son propre calcul de frontières, si bien qu’une personne courant avec deux applications voyait deux « zone 3 » différentes. Aucune donnée de zone ne vivait dans HealthKit, donc rien n’était synchronisé ni portable.

iOS 27 introduit HKWorkoutZoneConfiguration, une structure qui définit un ensemble complet de zones pour un type de quantité.2 La configuration porte un tableau ordonné de zones et identifie le type de quantité auquel elle s’applique. Le changement qui compte concerne l’origine des zones. La documentation d’Apple précise que le système génère automatiquement les zones à partir des indicateurs de santé d’une personne ; que celle-ci peut configurer les zones manuellement dans les réglages de Santé ; ou qu’une application peut fournir des zones personnalisées pour des entraînements précis.2 Les définitions de zone cessent d’être un détail privé de chaque application et deviennent un état partagé dont le framework est propriétaire.

import HealthKit

let heartRateType = HKQuantityType(.heartRate)

// A custom configuration an app supplies for one workout.
// makeIntervalZones is your own builder; construct the configuration
// from the ordered zones your workout uses, per HKWorkoutZoneConfiguration's
// declaration. The configuration identifies the quantity type the zones apply to.
let configuration: HKWorkoutZoneConfiguration = makeIntervalZones(for: heartRateType)

La structure complémentaire est HKWorkoutZoneGroup, qui contient la configuration de zones et les données de temps par zone pour un type de quantité.3 Un groupe de zones combine un HKWorkoutZoneConfiguration avec les données de temps par zone, de sorte que la lecture d’un groupe vous fournit à la fois les frontières et la durée que la personne a passée dans chacune d’elles. La documentation d’Apple décrit l’accès aux groupes de zones depuis les instances d’entraînement terminé pour récupérer les données de zone des entraînements achevés, et depuis une source d’entraînement en direct pour obtenir des informations de zone en temps réel pendant une séance active.3 Le framework se charge de la répartition. Votre code lit le résultat.

Watch on Apple Developer ↗
Apple montre les données de zone circulant des réglages de Santé d’une personne vers l’application, le temps passé dans chaque zone étant calculé par HealthKit à partir des échantillons entrants.

Dans la session 207, Apple indique qu’avec les zones d’entraînement intégrées à HealthKit, le temps passé dans chaque zone est calculé automatiquement à partir des échantillons entrants pendant l’entraînement ; l’application lit donc des durées pré-additionnées depuis zoneGroupsByType au lieu de répartir elle-même les échantillons de fréquence cardiaque.8

import HealthKit

func summarize(_ group: HKWorkoutZoneGroup) {
    // The group bundles the configuration (the zone boundaries)
    // with the time-in-zone data the framework already computed.
    let configuration = group.configuration

    for zone in group.zones {
        // Render each zone's accumulated time. No sample-walking,
        // no manual bucketing — the durations arrive pre-summed.
        render(zone)
    }
}

La troisième pièce relie la configuration à la personne plutôt qu’à l’application. preferredWorkoutZoneConfiguration(for:) est une méthode d’instance sur HKHealthStore qui renvoie la configuration de zones préférée d’une personne pour le type de quantité spécifié :4

func preferredWorkoutZoneConfiguration(
    for quantityType: HKQuantityType
) async throws -> HKWorkoutZoneConfiguration?

La documentation d’Apple détaille le contrat de retour : la méthode renvoie les zones configurées manuellement par la personne dans les réglages de Santé, ou les zones générées par le système si la personne n’a pas défini de valeurs personnalisées, ou nil si elle n’a pas du tout configuré de zones pour ce type de quantité.4 Les zones générées par le système se mettent à jour périodiquement à mesure que les indicateurs de santé de la personne évoluent ; les zones définies à la main restent constantes jusqu’à ce que la personne les modifie de nouveau. L’intention documentée est que les applications affichent des informations de zone alignées sur les préférences de la personne, sur l’ensemble des entraînements.4 Recourez à cette méthode lorsque vous voulez que votre zone 3 corresponde à celle que la personne voit partout ailleurs, au lieu d’inventer la vôtre.

import HealthKit

let store = HKHealthStore()
let heartRateType = HKQuantityType(.heartRate)

func loadPreferredZones() async throws -> HKWorkoutZoneConfiguration? {
    // nil means the person has not configured zones for heart rate.
    // Fall back to your own defaults only in that case.
    try await store.preferredWorkoutZoneConfiguration(for: heartRateType)
}

L’asymétrie mérite d’être nommée. preferredWorkoutZoneConfiguration(for:) lit la préférence permanente de la personne, ce qui dessine des graphiques cohérents avant, pendant et après un entraînement. Un HKWorkoutZoneConfiguration personnalisé que vous construisez vous-même couvre le cas où un entraînement précis nécessite des zones différentes de la valeur par défaut de la personne, comme une séance d’intervalles structurée avec ses propres bandes. La plupart des applications veulent la configuration préférée ; le chemin personnalisé sert lorsque la structure d’un entraînement exige ses propres zones.

Nouveaux types de catégorie : menopausalState et bleedingAfterMenopause

Le modèle de suivi du cycle de HealthKit gérait la menstruation, mais il n’offrait aucun moyen typé d’enregistrer où une personne se situait dans la transition ménopausique, ni d’enregistrer des saignements survenant après la fin des menstruations. iOS 27 ajoute les deux sous forme de types de catégorie, en suivant le même schéma HKCategorySample que l’article HealthKit pour iOS 26 couvrait pour les séances de pleine conscience et le sommeil.

menopausalState est un identifiant de type de catégorie pour les échantillons qui enregistrent l’état ménopausique d’une personne.5 Chaque échantillon est une entrée à un instant précis, et la documentation d’Apple impose une contrainte stricte : la date de début doit être égale à la date de fin, et enregistrer un échantillon où les deux diffèrent produit une erreur.5 La valeur de chaque échantillon est un cas de l’énumération HKCategoryValueMenopausalState, qui indique l’état ménopausique à un instant donné.6 Comme la liste des cas de la fiche technique est omise dans l’exposé d’Apple, considérez l’énumération comme la source de vérité pour les valeurs valides plutôt que de deviner les noms des cas ; le comportement documenté est que chaque échantillon stocke l’un de ces cas à une date précise.6

import HealthKit

let store = HKHealthStore()
let menopausalType = HKCategoryType(.menopausalState)

func record(state: HKCategoryValueMenopausalState, on date: Date) async throws {
    // Point-in-time sample: start and end MUST be identical.
    // A mismatched start/end is a save error, by documented design.
    let sample = HKCategorySample(
        type: menopausalType,
        value: state.rawValue,
        start: date,
        end: date
    )
    try await store.save(sample)
}

Le modèle à instant précis façonne la manière dont vous interprétez les données. La documentation d’Apple note que les applications peuvent lire plusieurs échantillons au fil du temps pour en dériver des interprétations de plus haut niveau : périodes actives, transitions, ou état courant.6 Un échantillon unique affirme qu’un état particulier s’appliquait à une date particulière, et le framework laisse à l’application le soin d’assembler les échantillons en une chronologie. Apple présente chaque entrée comme un changement d’état, une confirmation qu’un état s’appliquait à cette date, ou les deux, selon la façon dont l’application lit la série.5

bleedingAfterMenopause est un identifiant de type de catégorie pour les échantillons qui enregistrent les saignements après la ménopause.7 La distinction clinique est la raison de son existence comme type à part entière. Après la ménopause, la menstruation a cessé ; un saignement post-ménopausique n’est donc ni un flux menstruel ni un saignement intermenstruel ; la documentation d’Apple le qualifie de cliniquement distinct des deux.7 Contrairement à l’échantillon d’état ménopausique à instant précis, un échantillon bleedingAfterMenopause représente un intervalle de saignement et stocke une valeur d’intensité.7

import HealthKit

let store = HKHealthStore()
let bleedingType = HKCategoryType(.bleedingAfterMenopause)

// `intensityValue` is the raw value of the intensity enum Apple defines for
// the bleedingAfterMenopause type; confirm the concrete case set in its declaration.
func record(intensityValue: Int, from start: Date, to end: Date) async throws {
    // An interval sample, not point-in-time: start and end differ,
    // and the value carries the bleeding intensity.
    let sample = HKCategorySample(
        type: bleedingType,
        value: intensityValue,
        start: start,
        end: end
    )
    try await store.save(sample)
}

La séparation entre les deux types reflète celle que l’article iOS 26 traçait entre les échantillons de catégorie à instant précis et ceux par intervalle. menopausalState réduit sa fenêtre à un instant unique et porte un état. bleedingAfterMenopause conserve une véritable fenêtre [début, fin] et porte une intensité. Choisir la mauvaise forme pour l’un ou l’autre, c’est une erreur d’enregistrement ou un relevé dénué de sens ; le type que vous choisissez encode donc la nature de la donnée avant même d’écrire une ligne de code de requête.

Trajectoire d’adoption

Une application d’entraînement ou de santé qui embarque déjà HealthKit ajoute la surface d’iOS 27 de façon incrémentale ; rien de tout cela ne réécrit la tuyauterie d’autorisation ou d’enregistrement d’échantillons que l’article sur les patterns d’iOS 26 couvrait.

  1. Supprimez votre calcul de zones. Toute application qui calcule les zones de fréquence cardiaque à la main devrait appeler preferredWorkoutZoneConfiguration(for:) pour le type de quantité concerné et afficher la configuration renvoyée, en se rabattant sur vos propres valeurs par défaut uniquement lorsque l’appel renvoie nil.4 Vos zones correspondent désormais à celles que la personne voit à l’échelle du système.
  2. Lisez HKWorkoutZoneGroup au lieu de répartir les échantillons. Pour les récapitulatifs d’entraînement terminé, récupérez le groupe de zones et affichez ses données de temps par zone déjà calculées, plutôt que de parcourir les échantillons bruts de fréquence cardiaque et d’accumuler vous-même les durées.3
  3. Ne fournissez un HKWorkoutZoneConfiguration personnalisé que lorsqu’un entraînement nécessite ses propres bandes. Les séances d’intervalles structurées dotées de zones sur mesure justifient une configuration personnalisée ; tout le reste utilise la configuration préférée de la personne.2
  4. Ajoutez les nouveaux types de catégorie à votre demande d’autorisation. Une application de suivi du cycle ajoute menopausalState et bleedingAfterMenopause à ses ensembles de partage et de lecture, puis enregistre menopausalState comme des échantillons à instant précis (début égal à fin) et bleedingAfterMenopause comme des échantillons par intervalle assortis d’une intensité.57
  5. Vérifiez vos dates de début/fin selon le type. L’enregistrement de l’état ménopausique échoue si le début et la fin diffèrent ; l’échantillon de saignement est un intervalle et attend qu’ils diffèrent. Réglez correctement la forme de la fenêtre avant de livrer le chemin d’enregistrement.57

FAQ

Dois-je encore calculer moi-même les zones de fréquence cardiaque dans iOS 27 ?

Non, pas dans le cas courant. preferredWorkoutZoneConfiguration(for:) renvoie la configuration de zones préférée de la personne pour un type de quantité (ses zones configurées manuellement dans les réglages de Santé, ou les zones générées par le système, ou nil si elle n’en a configuré aucune), et HKWorkoutZoneGroup porte les données de temps par zone que le framework a déjà calculées pour un entraînement.34 Vous ne calculez les zones vous-même que lorsqu’un entraînement précis nécessite des bandes personnalisées différentes de la valeur par défaut de la personne ; dans ce cas, vous construisez un HKWorkoutZoneConfiguration pour cet entraînement.2

Quelle est la différence entre HKWorkoutZoneConfiguration et HKWorkoutZoneGroup ?

HKWorkoutZoneConfiguration définit un ensemble complet de zones pour un type de quantité : les zones ordonnées et le type de quantité auquel elles s’appliquent.2 HKWorkoutZoneGroup contient à la fois cette configuration et les données de temps par zone pour un type de quantité, de sorte qu’un groupe vous indique les frontières et la durée que la personne a passée dans chaque zone.3 Vous lisez les groupes de zones depuis les instances d’entraînement terminé pour les séances achevées, et depuis une source en direct pour des informations de zone en temps réel.3

Que renvoie preferredWorkoutZoneConfiguration(for:) lorsque la personne n’a jamais configuré de zones ?

Elle renvoie les zones générées par le système si la personne n’a pas défini de valeurs personnalisées, et nil uniquement si la personne n’a pas du tout configuré de zones pour ce type de quantité.4 Lorsque la personne a défini ses zones manuellement dans les réglages de Santé, la méthode renvoie celles-ci, et elles restent constantes jusqu’à ce que la personne les modifie ; les zones générées par le système se mettent à jour périodiquement à mesure que ses indicateurs de santé évoluent.4 Branchez sur nil pour fournir vos propres valeurs de repli.

Pourquoi l’enregistrement d’un échantillon menopausalState échoue-t-il avec une erreur de date ?

Parce que menopausalState enregistre un état à un instant unique, le framework exige que la date de début et la date de fin de l’échantillon soient identiques, et un échantillon dont les dates diffèrent produit une erreur à l’enregistrement.5 Réglez les deux sur la même Date. Cette contrainte le distingue de bleedingAfterMenopause, qui représente un intervalle et attend que le début et la fin diffèrent.7

En quoi bleedingAfterMenopause diffère-t-il du flux menstruel ?

Après la ménopause, la menstruation a cessé ; un saignement post-ménopausique est donc cliniquement distinct du flux menstruel et du saignement intermenstruel, et c’est pour cette raison qu’Apple lui attribue un type de catégorie séparé.7 Chaque échantillon bleedingAfterMenopause stocke un intervalle et une valeur d’intensité, et pour le suivi d’état associé vous utilisez le type menopausalState.7

L’ensemble de la série Apple Ecosystem accompagne cet article : les patterns d’autorisation et de types d’échantillon HealthKit d’iOS 26 sur lesquels celui-ci s’appuie ; le cycle de vie d’un entraînement watchOS où naissent les données de zone pendant une séance en direct ; le contrat d’exécution de watchOS qui régit l’exécution en arrière-plan au poignet ; et les trois surfaces d’une application iOS qui placent HealthKit comme couche source de données. Le point d’entrée est la série Apple Ecosystem. Pour le contexte plus large d’iOS avec des agents IA, consultez le guide de développement d’agents iOS.

Références


  1. Documentation pour développeurs Apple : HealthKit. La référence du framework couvrant les types de quantité, les types de catégorie, les échantillons, ainsi que les ajouts d’iOS 27 sur les zones d’entraînement et la santé reproductive. 

  2. Documentation pour développeurs Apple : HKWorkoutZoneConfiguration (iOS 27.0). « Une structure qui définit un ensemble complet de zones pour un type de quantité. » Déclarée comme struct HKWorkoutZoneConfiguration ; contient un tableau ordonné de zones, identifie son type de quantité et prend en charge des zones générées par le système, configurées par la personne ou fournies par l’application. 

  3. Documentation pour développeurs Apple : HKWorkoutZoneGroup (iOS 27.0). « Une structure qui contient la configuration de zones et les données de temps par zone pour un type de quantité. » Déclarée comme struct HKWorkoutZoneGroup ; combine une configuration avec les données de temps par zone, accessible depuis les instances d’entraînement terminé et depuis les sources d’entraînement en direct. 

  4. Documentation pour développeurs Apple : preferredWorkoutZoneConfiguration(for:) (iOS 27.0). « Renvoie la configuration de zones préférée d’une personne pour le type de quantité spécifié. » Déclarée comme func preferredWorkoutZoneConfiguration(for quantityType: HKQuantityType) async throws -> HKWorkoutZoneConfiguration? ; renvoie les zones configurées manuellement, les zones générées par le système, ou nil

  5. Documentation pour développeurs Apple : menopausalState (iOS 27.0). « Un identifiant pour les échantillons qui enregistrent l’état ménopausique d’une personne. » Déclaré comme static let menopausalState: HKCategoryTypeIdentifier ; les échantillons à instant précis exigent des dates de début et de fin identiques, sans quoi l’enregistrement échoue. 

  6. Documentation pour développeurs Apple : HKCategoryValueMenopausalState (iOS 27.0). « Une valeur qui indique l’état ménopausique à un instant enregistré. » Déclarée comme enum HKCategoryValueMenopausalState ; les applications peuvent interroger plusieurs échantillons au fil du temps pour en dériver des périodes actives, des transitions ou un état courant. 

  7. Documentation pour développeurs Apple : bleedingAfterMenopause (iOS 27.0). « Un identifiant pour les échantillons qui enregistrent les saignements après la ménopause. » Déclaré comme static let bleedingAfterMenopause: HKCategoryTypeIdentifier ; cliniquement distinct du flux menstruel, chaque échantillon est un intervalle assorti d’une valeur d’intensité. 

  8. Apple, session 207 de la WWDC26, « Deliver workout insights with HealthKit workout zones ». developer.apple.com/videos/play/wwdc2026/207. Avec les zones de fréquence cardiaque et de puissance en cyclisme intégrées à HealthKit dans iOS 27, le temps passé dans chaque zone est calculé automatiquement à partir des échantillons entrants pendant l’entraînement, et une application le relit depuis le dictionnaire zoneGroupsByType sur HKWorkout ou HKWorkoutActivity

Articles connexes

SwiftData dans iOS 27 : observation et historique

iOS 27 dote SwiftData d'une observation des changements de premier ordre avec ResultsObserver, d'une observation de l'hi…

12 min de lecture

Les nouveautés de SwiftUI pour iOS 27

iOS 27 retravaille les listes, les documents, les barres d'outils et les erreurs de SwiftUI : réorganisation par glisser…

25 min de lecture

The Robots Are Taking Exams in My Search Console

First-party GSC data: 91% of 3.8M impressions fail a human-query filter. Exam questions, pasted errors, and agent sweeps…

10 min de lecture