HealthKit no iOS 27: zonas de treino e novos tipos
Por anos, o HealthKit carregou as zonas de frequência cardíaca de treino como cidadãs não oficiais: todo aplicativo de corrida e ciclismo que desenhava um gráfico de barras com cinco zonas calculava essas zonas por conta própria, puxava leituras brutas de frequência cardíaca em HKQuantitySample, agrupava cada uma contra limiares fixos no código ou inseridos pelo usuário, e somava manualmente o tempo em cada faixa. O iOS 27 acaba com esse trabalho artesanal. As zonas passam a ser um tipo estruturado do HealthKit que o sistema gera, que a pessoa pode editar nas Configurações de Saúde e que seu aplicativo lê de volta com o tempo em cada zona já contabilizado. A mesma versão adiciona dois tipos de categoria de saúde reprodutiva, menopausalState e bleedingAfterMenopause, que preenchem uma lacuna no modelo de rastreamento de ciclo do HealthKit.1
Dois fios atravessam as adições do iOS 27, e eles compartilham um mesmo formato. O fio das zonas de treino pega uma computação que os aplicativos costumavam ter como sua e a move para dentro do framework, onde a definição de zona de uma pessoa permanece consistente em todo aplicativo que a consulta. O fio dos novos tipos dá a estágios da vida que o HealthKit antes não conseguia representar uma amostra de categoria tipada. Ambos seguem a gramática existente do HealthKit: tipos de quantidade para valores medidos, tipos de categoria para eventos e estados. Este post percorre cada um deles à luz da documentação da Apple, com o enquadramento de sempre do cluster: o que um aplicativo que já entrega HealthKit precisa adicionar para ganhar cada capacidade.
TL;DR
HKWorkoutZoneConfigurationdefine um conjunto completo de zonas para um tipo de quantidade. O sistema gera zonas automaticamente a partir das métricas de saúde de uma pessoa, a pessoa pode editá-las nas Configurações de Saúde, e um aplicativo pode fornecer zonas personalizadas para um treino específico.2HKWorkoutZoneGroupcombina uma configuração de zona com seus dados de tempo em zona. Você os lê de volta de instâncias de treino concluído para obter as durações por zona que o framework já calculou, em vez de agrupar amostras de frequência cardíaca por conta própria.3preferredWorkoutZoneConfiguration(for:)emHKHealthStoreretorna a configuração de zona preferida da pessoa para um tipo de quantidade, de modo que seus gráficos fiquem alinhados com os limiares que ela vê em todos os outros lugares.4menopausalStatemais a enumeraçãoHKCategoryValueMenopausalStateregistram o estado menopausal em um ponto específico no tempo; a data de início e a data de término da amostra precisam ser idênticas, ou o salvamento falha.56bleedingAfterMenopauseregistra o sangramento pós-menopausa como um intervalo com um valor de intensidade, mantido clinicamente distinto do fluxo menstrual.7
As zonas de treino sempre couberam a você calcular
Antes do iOS 27, um aplicativo de treino que quisesse zonas de frequência cardíaca fazia o trabalho inteiro. Ele consultava os dados de frequência cardíaca em HKQuantitySample para o intervalo de tempo do treino, decidia onde ficavam os limites das zonas (220 menos a idade, percentuais do limiar de lactato, ou um valor que o usuário digitava em uma tela de configurações), percorria as amostras em ordem e acumulava os segundos passados em cada faixa. Cada aplicativo escolhia sua própria matemática de limites, então uma pessoa que corria com dois aplicativos via duas “Zona 3” diferentes. Nenhum dos dados de zona vivia no HealthKit, então nenhum deles sincronizava ou permanecia portátil.
O iOS 27 introduz HKWorkoutZoneConfiguration, uma estrutura que define um conjunto completo de zonas para um tipo de quantidade.2 A configuração carrega um array ordenado de zonas e identifica o tipo de quantidade ao qual se aplica. A mudança que importa é onde as zonas se originam. A documentação da Apple afirma que o sistema gera zonas automaticamente com base nas métricas de saúde de uma pessoa; que a pessoa pode configurar zonas manualmente nas Configurações de Saúde; ou que um aplicativo pode fornecer zonas personalizadas para treinos específicos.2 As definições de zona deixam de ser um detalhe privado de cada aplicativo e passam a ser um estado compartilhado de propriedade do framework.
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)
A estrutura complementar é HKWorkoutZoneGroup, que contém a configuração de zona e os dados de tempo em zona para um tipo de quantidade.3 Um grupo de zona combina um HKWorkoutZoneConfiguration com os dados de tempo por zona, de modo que ler um grupo entrega a você tanto os limites quanto quanto tempo a pessoa passou dentro de cada um. A documentação da Apple descreve o acesso a grupos de zona a partir de instâncias de treino concluído, para recuperar os dados de zona de treinos finalizados, e a partir de uma fonte de treino ao vivo, para obter informações de zona em tempo real durante uma sessão ativa.3 O framework faz o agrupamento. Seu código lê o resultado.
Na sessão 207, a Apple afirma que, com as zonas de treino integradas ao HealthKit, o tempo em cada zona é calculado automaticamente a partir das amostras recebidas durante o treino, de modo que o aplicativo lê durações já somadas de zoneGroupsByType em vez de agrupar amostras de frequência cardíaca por conta própria.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)
}
}
A terceira peça amarra a configuração à pessoa, e não ao aplicativo. preferredWorkoutZoneConfiguration(for:) é um método de instância em HKHealthStore que retorna a configuração de zona preferida de alguém para o tipo de quantidade especificado:4
func preferredWorkoutZoneConfiguration(
for quantityType: HKQuantityType
) async throws -> HKWorkoutZoneConfiguration?
A documentação da Apple detalha o contrato de retorno: o método devolve as zonas configuradas manualmente pela pessoa nas Configurações de Saúde, ou as zonas geradas pelo sistema caso a pessoa não tenha definido valores personalizados, ou nil caso ela não tenha configurado nenhuma zona para aquele tipo de quantidade.4 As zonas geradas pelo sistema se atualizam periodicamente conforme as métricas de saúde da pessoa mudam; as zonas que a pessoa definiu manualmente permanecem constantes até que ela as edite novamente. A intenção documentada é que os aplicativos exibam informações de zona alinhadas às preferências da pessoa em todos os treinos.4 Recorra ao método quando quiser que sua Zona 3 corresponda à Zona 3 que a pessoa vê em todos os outros lugares, em vez de inventar a sua própria.
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)
}
Vale nomear a assimetria. preferredWorkoutZoneConfiguration(for:) lê a preferência permanente da pessoa, o que desenha gráficos consistentes antes, durante e depois de um treino. Um HKWorkoutZoneConfiguration personalizado que você mesmo constrói cobre o caso em que um treino específico precisa de zonas que diferem do padrão da pessoa, como uma sessão estruturada de intervalos com suas próprias faixas. A maioria dos aplicativos quer a configuração preferida; o caminho personalizado serve para quando a estrutura de um treino exige suas próprias zonas.
Novos tipos de categoria: menopausalState e bleedingAfterMenopause
O modelo de rastreamento de ciclo do HealthKit dava conta da menstruação, mas não tinha uma forma tipada de registrar em que ponto da transição menopausal uma pessoa se encontrava, nem como registrar sangramentos que ocorrem depois que a menstruação terminou. O iOS 27 adiciona ambos como tipos de categoria, seguindo o mesmo padrão de HKCategorySample que o post sobre HealthKit no iOS 26 cobriu para sessões de atenção plena e sono.
menopausalState é um identificador de tipo de categoria para amostras que registram o estado menopausal de uma pessoa.5 Cada amostra é uma entrada em um ponto específico no tempo, e a documentação da Apple impõe uma restrição rígida: a data de início precisa ser igual à data de término, e salvar uma amostra em que as duas diferem produz um erro.5 O valor de cada amostra é um caso da enumeração HKCategoryValueMenopausalState, que indica o estado menopausal em um ponto registrado no tempo.6 Como a lista de casos da ficha técnica fica omitida na discussão da Apple, trate a enumeração como a fonte da verdade para os valores válidos, em vez de adivinhar nomes de casos; o comportamento documentado é que cada amostra armazena um desses casos em uma data específica.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)
}
O modelo de ponto no tempo molda como você interpreta os dados. A documentação da Apple observa que os aplicativos podem ler múltiplas amostras ao longo do tempo para derivar interpretações de nível mais alto: períodos ativos, transições, ou um estado atual.6 Uma única amostra afirma que um determinado estado se aplicou em uma determinada data, e o framework deixa para o aplicativo o trabalho de costurar as amostras em uma linha do tempo. A Apple enquadra cada entrada como uma mudança de estado, uma confirmação de que um estado se aplicava naquela data, ou ambos, dependendo de como o aplicativo lê a série.5
bleedingAfterMenopause é um identificador de tipo de categoria para amostras que registram sangramento depois da menopausa.7 A distinção clínica é a razão pela qual ele existe como um tipo próprio. Depois da menopausa, a menstruação terminou, então o sangramento pós-menopausa não é fluxo menstrual nem sangramento intermenstrual; a documentação da Apple o chama de clinicamente distinto de ambos.7 Ao contrário da amostra de estado menopausal em um ponto no tempo, uma amostra de bleedingAfterMenopause representa um intervalo de sangramento e armazena um valor de intensidade.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)
}
A divisão entre os dois tipos espelha a divisão que o post do iOS 26 traçou entre amostras de categoria de ponto no tempo e de intervalo. menopausalState colapsa sua janela em um único instante e carrega um estado. bleedingAfterMenopause mantém uma janela [start, end] real e carrega uma intensidade. Escolher o formato errado para qualquer um dos dois resulta em erro de salvamento ou em um registro sem sentido, de modo que o tipo que você escolhe codifica a natureza do dado antes mesmo de você escrever uma linha de código de consulta.
Caminho de adoção
Um aplicativo de treino ou de saúde que já entrega HealthKit adiciona a superfície do iOS 27 de forma incremental; nada disso reescreve o encanamento de autorização ou de salvamento de amostras que o post sobre os padrões do iOS 26 cobriu.
- Apague sua matemática de zonas. Qualquer aplicativo que calcule zonas de frequência cardíaca à mão deveria chamar
preferredWorkoutZoneConfiguration(for:)para o tipo de quantidade relevante e renderizar a configuração retornada, recorrendo aos seus próprios padrões apenas quando a chamada retornarnil.4 Suas zonas agora correspondem ao que a pessoa vê em todo o sistema. - Leia
HKWorkoutZoneGroupem vez de agrupar amostras. Para resumos de treino concluído, puxe o grupo de zona e renderize seus dados de tempo em zona já calculados, em vez de percorrer amostras brutas de frequência cardíaca e acumular durações por conta própria.3 - Forneça um
HKWorkoutZoneConfigurationpersonalizado apenas quando um treino precisar das suas próprias faixas. Sessões estruturadas de intervalos com zonas sob medida são o caso para uma configuração personalizada; todo o resto usa a configuração preferida da pessoa.2 - Adicione os novos tipos de categoria à sua solicitação de autorização. Um aplicativo de rastreamento de ciclo adiciona
menopausalStateebleedingAfterMenopauseaos seus conjuntos de compartilhamento e leitura, e então registramenopausalStatecomo amostras de ponto no tempo (início igual ao término) ebleedingAfterMenopausecomo amostras de intervalo com uma intensidade.57 - Audite suas datas de início/término por tipo. O salvamento do estado menopausal falha se o início e o término diferirem; a amostra de sangramento é um intervalo e espera que eles difiram. Acerte o formato da janela antes de entregar o caminho de salvamento.57
Perguntas frequentes
Ainda preciso calcular as zonas de frequência cardíaca por conta própria no iOS 27?
Não, não no caso comum. preferredWorkoutZoneConfiguration(for:) retorna a configuração de zona preferida da pessoa para um tipo de quantidade (as zonas configuradas manualmente por ela nas Configurações de Saúde, ou as zonas geradas pelo sistema, ou nil caso ela não tenha configurado nenhuma), e HKWorkoutZoneGroup carrega os dados de tempo em zona que o framework já calculou para um treino.34 Você calcula as zonas por conta própria apenas quando um treino específico precisa de faixas personalizadas que diferem do padrão da pessoa, caso em que você constrói um HKWorkoutZoneConfiguration para aquele treino.2
Qual é a diferença entre HKWorkoutZoneConfiguration e HKWorkoutZoneGroup?
HKWorkoutZoneConfiguration define um conjunto completo de zonas para um tipo de quantidade: as zonas ordenadas e o tipo de quantidade ao qual se aplicam.2 HKWorkoutZoneGroup contém tanto essa configuração quanto os dados de tempo em zona para um tipo de quantidade, de modo que um grupo informa a você os limites e quanto tempo a pessoa passou em cada zona.3 Você lê os grupos de zona a partir de instâncias de treino concluído para sessões finalizadas e a partir de uma fonte ao vivo para informações de zona em tempo real.3
O que preferredWorkoutZoneConfiguration(for:) retorna quando a pessoa nunca configurou zonas?
Ele retorna as zonas geradas pelo sistema caso a pessoa não tenha definido valores personalizados, e nil somente se a pessoa não tiver configurado nenhuma zona para aquele tipo de quantidade.4 Quando a pessoa definiu zonas manualmente nas Configurações de Saúde, o método retorna essas zonas, e elas permanecem constantes até que a pessoa as edite; as zonas geradas pelo sistema se atualizam periodicamente conforme as métricas de saúde da pessoa mudam.4 Faça a ramificação em nil para fornecer seus próprios padrões de fallback.
Por que salvar uma amostra de menopausalState falha com um erro de data?
Porque menopausalState registra um estado em um único ponto no tempo, o framework exige que a data de início e a data de término da amostra sejam idênticas, e uma amostra cujas datas diferem produz um erro no salvamento.5 Defina ambas com a mesma Date. Essa restrição a distingue de bleedingAfterMenopause, que representa um intervalo e espera que o início e o término difiram.7
Como bleedingAfterMenopause difere do fluxo menstrual?
Depois da menopausa, a menstruação terminou, então o sangramento pós-menopausa é clinicamente distinto do fluxo menstrual e do sangramento intermenstrual; a Apple lhe dá um tipo de categoria separado por essa razão.7 Cada amostra de bleedingAfterMenopause armazena um intervalo e um valor de intensidade, e, para o rastreamento de estado relacionado, você usa o tipo menopausalState.7
O cluster completo do Apple Ecosystem fica ao lado deste post: os padrões de autorização e de tipos de amostra do HealthKit no iOS 26 sobre os quais este se apoia; o ciclo de vida de treino no watchOS onde os dados de zona se originam durante uma sessão ao vivo; o contrato de ambiente de execução do watchOS que governa a execução em segundo plano no pulso; e as três superfícies de um aplicativo iOS que situam o HealthKit como a camada de fonte de dados. O hub é a Série Apple Ecosystem. Para o contexto mais amplo de iOS com agentes de IA, veja o guia de Desenvolvimento de Agentes iOS.
Referências
-
Documentação para Desenvolvedores da Apple: HealthKit. A referência do framework cobrindo tipos de quantidade, tipos de categoria, amostras e as adições de zonas de treino e saúde reprodutiva do iOS 27. ↩
-
Documentação para Desenvolvedores da Apple:
HKWorkoutZoneConfiguration(iOS 27.0). “Uma estrutura que define um conjunto completo de zonas para um tipo de quantidade.” Declarada comostruct HKWorkoutZoneConfiguration; contém um array ordenado de zonas, identifica seu tipo de quantidade e suporta zonas geradas pelo sistema, configuradas pela pessoa ou personalizadas fornecidas pelo aplicativo. ↩↩↩↩↩↩ -
Documentação para Desenvolvedores da Apple:
HKWorkoutZoneGroup(iOS 27.0). “Uma estrutura que contém a configuração de zona e os dados de tempo em zona para um tipo de quantidade.” Declarada comostruct HKWorkoutZoneGroup; combina uma configuração com dados de tempo em zona, acessível a partir de instâncias de treino concluído e de fontes de treino ao vivo. ↩↩↩↩↩↩↩ -
Documentação para Desenvolvedores da Apple:
preferredWorkoutZoneConfiguration(for:)(iOS 27.0). “Retorna a configuração de zona preferida de alguém para o tipo de quantidade especificado.” Declarado comofunc preferredWorkoutZoneConfiguration(for quantityType: HKQuantityType) async throws -> HKWorkoutZoneConfiguration?; retorna zonas configuradas manualmente, zonas geradas pelo sistema, ounil. ↩↩↩↩↩↩↩↩ -
Documentação para Desenvolvedores da Apple:
menopausalState(iOS 27.0). “Um identificador para amostras que registram o estado menopausal de uma pessoa.” Declarado comostatic let menopausalState: HKCategoryTypeIdentifier; amostras de ponto no tempo exigem datas de início e término idênticas, ou o salvamento falha. ↩↩↩↩↩↩↩ -
Documentação para Desenvolvedores da Apple:
HKCategoryValueMenopausalState(iOS 27.0). “Um valor que indica o estado menopausal em um ponto registrado no tempo.” Declarado comoenum HKCategoryValueMenopausalState; os aplicativos podem consultar múltiplas amostras ao longo do tempo para derivar períodos ativos, transições ou o estado atual. ↩↩↩↩ -
Documentação para Desenvolvedores da Apple:
bleedingAfterMenopause(iOS 27.0). “Um identificador para amostras que registram sangramento depois da menopausa.” Declarado comostatic let bleedingAfterMenopause: HKCategoryTypeIdentifier; clinicamente distinto do fluxo menstrual, cada amostra é um intervalo com um valor de intensidade. ↩↩↩↩↩↩↩↩↩ -
Apple, sessão 207 da WWDC26, “Deliver workout insights with HealthKit workout zones.” developer.apple.com/videos/play/wwdc2026/207. Com as zonas de frequência cardíaca e de potência de ciclismo integradas ao HealthKit no iOS 27, o tempo em cada zona é calculado automaticamente com base nas amostras recebidas durante o treino, e um aplicativo o lê de volta do dicionário
zoneGroupsByTypeemHKWorkoutouHKWorkoutActivity. ↩