Dunfey · Hotel WWDC as data, est. 1983
Front desk everything
Years
Topics

2024 App ServicesHealth & Fitness

WWDC24 · 14 min · App Services / Health & Fitness

Explore wellbeing APIs in HealthKit

Learn how to incorporate mental health and wellbeing into your app using HealthKit. There are new APIs for State of Mind, as well as for Depression Risk and Anxiety Risk. We’ll dive into principles of emotion science to cover how reflecting on feelings can be beneficial, and how State of Mind can be used to represent different types of mood and emotion.

Watch at developer.apple.com ↗

Transcript all transcripts

Chapters

Code shown on screen · 9 snippets

Request authorization to read and write State of Mind HealthKit samples swift · at 5:37 ↗
// Request authorization to read and write State of Mind HealthKit samples

import HealthKitUI

func healthDataAccessRequest(
    store: HKHealthStore, 
    shareTypes: Set<HKSampleType>,
    readTypes: Set<HKObjectType>? = nil,
    trigger: some Equatable,
    completion: @escaping (Result<Bool, any Error>) -> Void
) -> some View
EmojiType swift · at 6:26 ↗
// EmojiType

enum EmojiType: CaseIterable {
    case angry
    case sad
    case indifferent
    case satisfied
    case happy
    
    var emoji: String {
        switch self {
        case .angry: return "😡"
        case .sad: return "😢"
        case .indifferent: return "😐"
        case .satisfied: return "😌"
        case .happy: return "😊"
        }
    }
  
}
Create State of Mind sample for an event and emoji selection swift · at 6:32 ↗
/// Create State of Mind sample for an event and emoji selection

func createSample(for event: EventModel, emojiType: EmojiType) ->
HKStateOfMind {
    let kind: HKStateOfMind.Kind = .momentaryEmotion
    let valence: Double = emojiType.valence
    let label = emojiType.label
    let association = event.association
    return HKStateOfMind(date: event.endDate,
                         kind: kind,
                         valence: valence,
                         labels: [label],
                         associations: [association])
}
Save State of Mind sample from emoji choice swift · at 7:21 ↗
// Save State of Mind sample from emoji choice

func save(sample: HKSample, healthStore: HKHealthStore) async {
    do {
        try await healthStore.save(sample)
    }
    catch {
        // Handle error here.
    }
}
Query State of Mind samples swift · at 10:34 ↗
// Query State of Mind samples

let datePredicate: NSPredicate = { ... }
let associationsPredicate = NSCompoundPredicate (
    orPredicateWithSubpredicates: associations.map {
        HKQuery.predicateForStatesOfMind(with: $0)
    }
)  
let compoundPredicate = NSCompoundPredicate(
    andPredicateWithSubpredicates: [datePredicate, associationsPredicate]
)
let state0fMindPredicate = HKSamplePredicate.stateOfMind(compoundPredicate)
Query State of Mind samples swift · at 10:49 ↗
// Query State of Mind samples

let datePredicate: NSPredicate = { ... }
let associationsPredicate = NSCompoundPredicate (
    orPredicateWithSubpredicates: associations.map {
        HKQuery.predicateForStatesOfMind(with: $0)
    }
)  
let compoundPredicate = NSCompoundPredicate(
    andPredicateWithSubpredicates: [datePredicate, associationsPredicate]
)
let stateOfMindPredicate = HKSamplePredicate.stateOfMind(compoundPredicate)

let descriptor = HKSampleQueryDescriptor(predicates: [stateOfMindPredicate],
                                         sortDescriptors: [])
var results: [HKStateOfMind] = []
do {
    // Launch the query and wait for the results.
    results = try await descriptor.result(for: healthStore)
} catch {
    // Handle error here.
Query State of Mind samples (continued) swift · at 10:54 ↗
// Adjust each valence value to be from a range of 0.0 to 2.0.
let adjustedValenceResults = results.map { $0.valence + 1.0 }
// Calculate average valence.
let totalAdjustedValence = adjustedValenceResults.reduce (0.0, +)
let averageAdjustedValence = totalAdjustedValence / Double(results.count)
// Convert valence to percentage.
let adjustedValenceAsPercent = Int(100.0 * (averageAdjustedValence / 2.0))
Query for relevant State of Mind samples with a specific label swift · at 11:33 ↗
// Query for relevant State of Mind samples with a specific label
let label: HKStateOfMind.Label = .happy

// Configure the query
let datePredicate = HKQuery.predicateForSamples(withStart: dateInterval.start,
                                                end: dateInterval.end)
let associationPredicate = HKQuery.predicateForStatesOfMind(with: association)
let labelPredicate = HKQuery.predicateForStates0fMind(with: label)
let compoundPredicate = NSCompoundPredicate(
    andPredicateWithSubpredicates: [datePredicate, associationPredicate, labelPredicate]
)
let stateOfMindPredicate = HKSamplePredicate.stateOfMind(compoundPredicate)
let descriptor = HKAnchoredObjectQueryDescriptor(predicates: [state0fMindPredicate],
                                                 anchor: nil)

// Fetch the results
let results = descriptor.results(for: healthStore)
let samples: [HKStateOfMind] = try await results.reduce([]) { $1.addedSamples }
Process State of Mind sample data swift · at 11:45 ↗
// Process State of Mind sample data

let happiestSample = samples.max { $0.valence < $1. valence }
let happiestEvent: EventModel? = findClosestEvent(startDate: happiestSample?.startDate,
                                                  endDate: happiestSample?.endDate)

Resources