AnpherosAnpheros PlatformDevelopers

Try it free in the sandbox · first FHIR call in 5 minutesFree · 30 synthetic patients · no card

Apple Health (HealthKit) и FHIR

Читайте данные Apple Watch и Apple Health через HealthKit на Swift, по местному времени, и записывайте их в FHIR R4: разрешения, фоновая синхронизация, правила Apple.

Данные Apple Watch хранятся в Apple Health на сопряженном iPhone, и единственный способ их прочитать — это HealthKit, из приложения на этом iPhone, с разрешения пользователя. Чтобы поместить их в запись FHIR, читайте ежедневную статистику с помощью HKStatisticsCollectionQuery, отправляйте значения на ваш бэкенд и записывайте каждую метрику как Observation с кодом LOINC и единицей измерения UCUM. На этой странице показан код на Swift (проверенный на соответствие SDK iOS 17), разрешения и правила, установленные Apple, а также как значения становятся FHIR R4 Observations.

Что содержится в Apple Health

Apple Health собирает данные, которые измеряют iPhone и Apple Watch — частоту сердечных сокращений, частоту сердечных сокращений в покое, вариабельность сердечного ритма (SDNN), уровень кислорода в крови, частоту дыхания, шаги, расход энергии, стадии сна, уведомления о нерегулярном ритме, записи ЭКГ — а также данные, которые записывают другие приложения: Garmin Connect, Oura, Withings Health Mate, умные весы, тонометры, глюкометры. Таким образом, чтение данных Apple Health охватывает больше, чем только данные Apple Watch.

Сервера HealthKit или веб-API не существует. Данные остаются на устройстве (и в зашифрованной резервной копии iCloud пользователя); ваше приложение считывает их локально.

Разрешения

  1. Включите возможность HealthKit в Xcode и добавьте NSHealthShareUsageDescription в Info.plist (плюс NSHealthUpdateUsageDescription, только если вы пишете).
  2. Запросите необходимые типы. Пользователи могут разрешить одни типы и отказаться от других, при этом HealthKit не сообщает вашему приложению, был ли отклонен доступ на чтение: отклоненный тип просто возвращает пустые данные. Разработайте экраны для случая "нет данных", а не для ошибки.
  3. Запрашивайте разрешения в момент подключения пользователя, с пояснением причины, а не при первом запуске приложения.

Чтение ежедневных значений в Swift

import Foundation
import HealthKit

/// One day of Apple Health data, ready to send to your backend.
struct DailyValue: Codable {
    let metric: String      // "heart_rate", "steps"
    let day: String         // "2026-10-01", the user's local day
    let value: Double
    let min: Double?
    let max: Double?
}

let store = HKHealthStore()
let heartRate = HKQuantityType(.heartRate)
let steps = HKQuantityType(.stepCount)

func requestAccess() async throws {
    // Read-only: the app never writes to Apple Health.
    try await store.requestAuthorization(toShare: [], read: [heartRate, steps])
}

/// Daily statistics for the last `days` days, one value per local calendar day.
func dailyValues(_ type: HKQuantityType, metric: String, unit: HKUnit,
                 options: HKStatisticsOptions, days: Int) async throws -> [DailyValue] {
    let calendar = Calendar.current
    let end = calendar.startOfDay(for: Date()).addingTimeInterval(86_400)
    let start = calendar.date(byAdding: .day, value: -days, to: end)!
    let query = HKStatisticsCollectionQueryDescriptor(
        predicate: HKSamplePredicate.quantitySample(type: type,
                                                    predicate: HKQuery.predicateForSamples(withStart: start, end: end)),
        options: options,
        anchorDate: start,
        intervalComponents: DateComponents(day: 1))
    let collection = try await query.result(for: store)
    let fmt = DateFormatter()
    fmt.dateFormat = "yyyy-MM-dd"
    var out: [DailyValue] = []
    collection.enumerateStatistics(from: start, to: end) { stats, _ in
        let day = fmt.string(from: stats.startDate)
        if options.contains(.cumulativeSum), let sum = stats.sumQuantity() {
            out.append(DailyValue(metric: metric, day: day, value: sum.doubleValue(for: unit), min: nil, max: nil))
        } else if let avg = stats.averageQuantity() {
            out.append(DailyValue(metric: metric, day: day, value: avg.doubleValue(for: unit),
                                  min: stats.minimumQuantity()?.doubleValue(for: unit),
                                  max: stats.maximumQuantity()?.doubleValue(for: unit)))
        }
    }
    return out
}

func collect() async throws -> [DailyValue] {
    try await requestAccess()
    let bpm = HKUnit.count().unitDivided(by: .minute())
    let hr = try await dailyValues(heartRate, metric: "heart_rate", unit: bpm,
                                   options: [.discreteAverage, .discreteMin, .discreteMax], days: 30)
    let st = try await dailyValues(steps, metric: "steps", unit: .count(), options: .cumulativeSum, days: 30)
    return hr + st   // POST these to your backend, which writes them to the FHIR record
}

Почему статистические запросы вместо чтения выборок: HKStatisticsCollectionQuery возвращает итоговые данные и средние значения за день, которые Apple Health уже дедуплицировал по источникам, поэтому шаги, подсчитанные как iPhone, так и Watch, не суммируются дважды. Чтение необработанных выборок и их самостоятельное суммирование является наиболее распространенным источником завышенного количества шагов.

Дни — это местные календарные дни человека (Calendar.current). Сохраняйте их такими же до записи FHIR, где effectivePeriod объекта Observation представляет собой этот местный день с его смещением часового пояса.

Поддержание актуальности записи

От значений Swift к FHIR Observations

Отправьте массив DailyValue на ваш бэкенд и запишите одно Observation для каждого человека, метрики и дня со стабильным идентификатором, обновляя его, когда наступает тот же день снова. Таблица сопоставления (тип HealthKit → LOINC → UCUM), проверенный пример JSON и код TypeScript, выполняющий это обновление (upsert), запускаемый на платформе, находятся в разделе Wearable data in FHIR. Коды для двух метрик здесь:

HealthKit LOINC UCUM Значение за день
heartRate 8867-4 Heart rate /min среднее, с минимумом и максимумом в качестве компонентов
stepCount 41950-7 Number of steps in 24 hour {steps} общее

Правила Apple для медицинских данных

Apple Health Records

Отдельно от данных о физической активности, Apple Health может хранить клинические записи, загруженные из участвующих медицинских систем (в основном в США), и HealthKit предоставляет их в виде объектов HKClinicalRecord, которые содержат исходный ресурс FHIR. Для их чтения требуются отдельные разрешения и права доступа. Это другая интеграция по сравнению с данными с носимых устройств, и Anpheros Daily в настоящее время их не считывает.

Место Anpheros в системе

Платформа Anpheros хранит результат: запись FHIR R4 о человеке, где каждое значение с носимого устройства представлено как Observation, помеченное как данные устройства, согласие для других приложений, информация о происхождении (provenance) и журнал доступа. Anpheros не читает Apple Health напрямую — это происходит в вашем iOS-приложении. Собственное приложение Anpheros, Anpheros Daily, читает Apple Health на iPhone (планы Plus и Max) и записывает ежедневные сводки в запись с указанными выше кодами.

Часто задаваемые вопросы

Могу ли я читать данные Apple Watch с сервера?

Нет. Данные Apple Watch синхронизируются с Apple Health на сопряженном iPhone, и HealthKit может использоваться только приложением на этом устройстве. Приложение считывает данные и отправляет их на ваш сервер.

Существует ли веб-API или REST API для Apple Health?

Нет. Apple не предлагает веб- или REST API для Apple Health: HealthKit работает только внутри приложения на iPhone (или Apple Watch) пользователя. Чтобы использовать данные на сервере, ваше приложение считывает их с разрешения пользователя и отправляет, например, в виде FHIR Observations в Anpheros.

Нужен ли мне API-ключ или плата за Apple Health API?

Ключ и плата не требуются: HealthKit является частью iOS. Вам потребуется возможность HealthKit в вашем приложении, описание использования для каждого типа данных и разрешение пользователя; проверка App Store проверяет, как вы используете данные.

Как узнать, отказал ли пользователь в доступе к типу HealthKit?

Вы не можете узнать об этом для доступа на чтение: HealthKit скрывает эту информацию для защиты конфиденциальности, и отказанный тип не возвращает никаких данных. Обрабатывайте "нет данных" как нормальное состояние и предоставьте способ просмотра разрешений в приложении Health.

Почему мои счетчики шагов выше, чем в приложении Health?

Вероятно, вы суммируете необработанные выборки из нескольких источников (iPhone и Watch). Используйте HKStatisticsCollectionQuery с .cumulativeSum, что применяет собственное дедупликацию Apple Health.

Какой код LOINC соответствует вариабельности сердечного ритма Apple Watch?

Apple Health хранит HRV как SDNN, что соответствует LOINC 80404-7. Health Connect хранит RMSSD, другую статистику, поэтому не смешивайте их под одним кодом.

Связанные материалы

Try it free in the sandbox · first FHIR call in 5 minutesFree · 30 synthetic patients · no card

Product updates by email

New features, guides and the end of the beta. One email a month at most.

Send me occasional Anpheros Platform updates by email (new features, API changes, guides). I'll confirm by email and can unsubscribe in one click from any email. Privacy