# Apple Health (HealthKit) in FHIR

> Leggi i dati di Apple Watch e Apple Health con HealthKit in Swift, per giorno locale, e scrivili in un record FHIR R4: permessi, sincronizzazione in background, regole di Apple.

Source: https://developers.anpheros.com/it/guides/apple-health-fhir

**I dati di Apple Watch risiedono in Apple Health sull'iPhone associato, e l'unico modo per leggerli è tramite HealthKit, da un'app su quell'iPhone, con il permesso della persona.** Per inserirli in un record FHIR, leggi le statistiche giornaliere con `HKStatisticsCollectionQuery`, invia i valori al tuo backend e scrivi ogni metrica come un'Observation con un codice LOINC e un'unità UCUM. Questa pagina mostra il codice Swift (type-checked rispetto all'SDK iOS 17), i permessi e le regole stabilite da Apple, e come i valori diventano FHIR R4 Observations.

## Cosa c'è in Apple Health

Apple Health raccoglie ciò che iPhone e Apple Watch misurano — frequenza cardiaca, frequenza cardiaca a riposo, variabilità della frequenza cardiaca (SDNN), ossigeno nel sangue, frequenza respiratoria, passi, energia, fasi del sonno, notifiche di ritmo irregolare, registrazioni ECG — e ciò che altre app scrivono: Garmin Connect, Oura, Withings Health Mate, bilance intelligenti, misuratori di pressione sanguigna, glucometri. Leggere Apple Health copre quindi più dell'Apple Watch.

Non esiste un server HealthKit o un'API web. I dati rimangono sul dispositivo (e nel backup crittografato di iCloud della persona); la tua app li legge localmente.

## Permessi

1. Attiva la funzionalità **HealthKit** in Xcode e aggiungi `NSHealthShareUsageDescription` a `Info.plist` (più `NSHealthUpdateUsageDescription` solo se scrivi).
2. Richiedi i tipi di cui hai bisogno. Le persone possono consentire alcuni tipi e rifiutarne altri, e **HealthKit non comunica alla tua app se l'accesso in lettura è stato rifiutato**: un tipo rifiutato restituisce semplicemente nessun dato. Progetta le schermate per la gestione di "nessun dato" piuttosto che per un errore.
3. Richiedi al momento in cui la persona si connette, con una frase che spieghi il motivo, non al primo avvio.

## Lettura dei valori giornalieri in Swift

```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
}
```

Perché query statistiche anziché leggere campioni: `HKStatisticsCollectionQuery` restituisce totali e medie giornalieri che Apple Health ha già de-duplicato tra le fonti, quindi i passi contati sia dall'iPhone che dall'Apple Watch non vengono aggiunti due volte. La lettura di campioni grezzi e la loro sommatoria manuale sono la causa più comune di conteggi dei passi gonfiati.

I giorni sono i giorni di calendario locali della persona (`Calendar.current`). Mantienili in questo modo fino al record FHIR, dove il `effectivePeriod` dell'Observation è quel giorno locale con il suo offset di fuso orario.

## Mantenere il record aggiornato

- **All'apertura:** leggi i giorni trascorsi dall'ultimo sync riuscito ogni volta che l'app va in primo piano. Questa è la base affidabile.
- **In background:** `HKObserverQuery` con `enableBackgroundDelivery(for:frequency:)` riattiva la tua app quando arrivano nuovi dati; richiede l'autorizzazione HealthKit per la consegna in background e iOS decide la tempistica effettiva.
- **Prima connessione:** importa una cronologia limitata (ad esempio 30 giorni) anziché anni, quindi procedi in avanti.

## Da valori Swift a Osservazioni FHIR

Invia l'array `DailyValue` al tuo backend e scrivi una Osservazione per persona, metrica e giorno con un identificatore stabile, aggiornandola quando lo stesso giorno si ripresenta. La tabella di mappatura (tipo HealthKit → LOINC → UCUM), un esempio JSON validato e il codice TypeScript che esegue questo upsert, eseguito sulla piattaforma, si trovano su [Dati indossabili in FHIR](https://developers.anpheros.com/it/guides/wearable-data-fhir). I codici per le due metriche qui sono:

| HealthKit | LOINC | UCUM | Valore per giorno |
|---|---|---|---|
| `heartRate` | 8867-4 Heart rate | `/min` | media, con minimo e massimo come componenti |
| `stepCount` | 41950-7 Number of steps in 24 hour | `{steps}` | totale |

## Regole di Apple per i dati sanitari

- Linea guida 5.1.3 per la revisione delle app: i dati sanitari non possono essere utilizzati per pubblicità o data mining, non possono essere condivisi con terze parti senza il consenso della persona e le informazioni sanitarie personali non possono essere archiviate in iCloud.
- La tua informativa sulla privacy deve indicare cosa leggi e perché; Apple controlla.
- I dati scritti dalla tua app su Apple Health sono attribuiti alla tua app; i dati che leggi mantengono la loro origine originale (`HKSource`), che dovresti riportare nel record come sistema di origine.

## Apple Health Records

Separately from fitness data, Apple Health can hold clinical records downloaded from participating health systems (mostly in the United States), and HealthKit exposes them as `HKClinicalRecord` objects that carry the original FHIR resource. Reading them needs its own permission and entitlement. They are a different integration from wearable data, and Anpheros Daily does not read them today.

## Dove si inserisce Anpheros

La Piattaforma Anpheros memorizza il risultato: il record FHIR R4 della persona, con ogni valore del dispositivo indossabile come Observation contrassegnato come dati del dispositivo, consenso per altre app, provenienza e un log di accesso. Non legge Apple Health direttamente: questo avviene nella tua app iOS. L'app di Anpheros, **Anpheros Daily**, legge Apple Health su iPhone (piani Plus e Max) e scrive riepiloghi giornalieri nel record con i codici sopra.

## Domande frequenti

### Posso leggere i dati di Apple Watch da un server?
No. I dati di Apple Watch vengono sincronizzati con Apple Health sull'iPhone associato e HealthKit può essere utilizzato solo da un'app su quel dispositivo. L'app legge i dati e li invia al tuo server.

### Esiste un'API web o REST per Apple Health?
No. Apple non offre un'API web o REST per Apple Health: HealthKit viene eseguito solo all'interno di un'app sull'iPhone (o Apple Watch) della persona. Per utilizzare i dati su un server, la tua app li legge con il permesso della persona e li invia, ad esempio come FHIR Observations ad Anpheros.

### Ho bisogno di una chiave API o devo pagare per l'API di Apple Health?
Nessuna chiave e nessuna commissione: HealthKit fa parte di iOS. Hai bisogno della capacità HealthKit nella tua app, una descrizione dell'uso per ogni tipo di dato e il permesso della persona; la revisione dell'App Store controlla come utilizzi i dati.

### Come faccio a sapere se la persona ha rifiutato l'accesso a un tipo HealthKit?
Non puoi, per l'accesso in lettura: HealthKit lo nasconde per proteggere la privacy e un tipo rifiutato non restituisce dati. Tratta "nessun dato" come uno stato normale e offri un modo per rivedere le autorizzazioni nell'app Salute.

### Perché i miei conteggi di passi sono più alti rispetto all'app Salute?
Probabilmente stai sommando campioni grezzi da diverse fonti (iPhone e Watch). Utilizza `HKStatisticsCollectionQuery` con `.cumulativeSum`, che applica la deduplicazione di Apple Health.

### Quale codice LOINC corrisponde alla variabilità della frequenza cardiaca di Apple Watch?
Apple Health memorizza l'HRV come SDNN, che corrisponde a LOINC 80404-7. Health Connect memorizza RMSSD, una statistica diversa, quindi non mescolare le due sotto un unico codice.

## Correlati

- [Dati indossabili in FHIR](https://developers.anpheros.com/it/guides/wearable-data-fhir): la tabella di mappatura e il codice backend
- [Health Connect in FHIR](https://developers.anpheros.com/it/guides/health-connect-fhir): lo stesso su Android
- [Come creare un'app di cartella clinica personale](https://developers.anpheros.com/it/guides/personal-health-record-app)
- [Come creare un'app sanitaria con Flutter](https://developers.anpheros.com/it/guides/healthcare-app-flutter)
