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 ↗Chapters
Code shown on screen · 9 snippets
Request authorization to read and write State of Mind HealthKit samples
// 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
// 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
/// 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
// 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
// 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
// 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)
// 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
// 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
// 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
Related sessions
-
16 min -
12 min -
32 min