Exploring MusicKit and Apple Music API
Unlock the full power of MusicKit & Apple Music APIs in your apps with the best guide! Use code musickit-blog for a limited-time 35% discount!
Apple provides the class HKActivitySummary
, which contains the move, exercise, and stand data for a given day. You can query the data using HKActivitySummaryQuery
and, most recently, use HKActivitySummaryQueryDescriptor
to get the sweet async/await syntax.
Permissions
The first thing is to make sure that you request authorization from the user to read the activity summary data:
let types = Set([HKObjectType.activitySummaryType()])
Date Range
After successful authorization, create a date range for fetching the activity summary. The example below fetches yesterday’s and the present day’s data:
let calendar = Calendar.autoupdatingCurrent
let yesterdayDate = calendar.date(byAdding: .day, value: -1, to: Date())
guard let yesterdayDate = yesterdayDate else { return }
var startComponents = calendar.dateComponents([.day, .month, .year], from: yesterdayDate)
startComponents.hour = 0
startComponents.minute = 0
startComponents.second = 0
var endComponents = startComponents
endComponents.day = 2 + (endComponents.day ?? 0)
Then, create a predicate for activity summaries between the two date components:
let predicate = HKQuery.predicate(forActivitySummariesBetweenStart: startComponents, end: endComponents)
Fetching the Data Using Closures
To initialize a new active summary query, you use the HKActivitySummaryQuery
with the results handler providing an array of HKActivitySummary
containing the activity summaries.
init(predicate: NSPredicate?, resultsHandler handler: @escaping (HKActivitySummaryQuery, [HKActivitySummary]?, Error?) -> Void)
The following example provides executing a query and printing the active energy burned and exercise minutes:
let query = HKActivitySummaryQuery(predicate: predicate) { (query, summaries, error) -> Void in
guard let summaries else { return }
for summary in summaries {
let activeEnergyBurned = summary.activeEnergyBurned.doubleValue(for: HKUnit.kilocalorie())
let exerciseMinutes = summary.appleExerciseTime.doubleValue(for: HKUnit.minute())
let standHours = summary.appleStandHours.doubleValue(for: HKUnit.hour())
debugPrint("activeEnergyBurned", activeEnergyBurned)
debugPrint("exerciseMinutes", exerciseMinutes)
debugPrint("standHours", standHours)
}
}
Like forgetting to write resume()
when working with network calls, DO NOT forget to call the store to execute the query after creating it:
var healthStore: HKHealthStore
store.execute(query)
Fetching the Data Using Modern Concurrency
With the latest async/await, HealthKit also got some upgrades; however, they are iOS 15.4+. After creating the predicate, you create a query descriptor:
let predicate = HKQuery.predicate(forActivitySummariesBetweenStart: startComponents, end: endComponents)
let activeSummaryDescriptor = HKActivitySummaryQueryDescriptor(predicate: predicate)
To get a snapshot of the activity summaries, you await the result, which is an array of activity summaries in the form of HKActivitySummary
objects:
var healthStore: HKHealthStore
let summaries = try await activeSummaryDescriptor.result(for: store)
If you want to make sure that no data is lost while the query is running, you can have an asynchronous sequence emit the array of summaries:
let activeSummaryQueue = activeSummaryDescriptor.results(for: store)
activeSummaryTask = Task {
for try await summaries in activeSummaryQueue {
for summary in summaries {
let activeEnergyBurned = summary.activeEnergyBurned.doubleValue(for: HKUnit.kilocalorie())
let exerciseMinutes = summary.appleExerciseTime.doubleValue(for: HKUnit.minute())
let standHours = summary.appleStandHours.doubleValue(for: HKUnit.hour())
debugPrint("activeEnergyBurned", activeEnergyBurned)
debugPrint("exerciseMinutes", exerciseMinutes)
debugPrint("standHours", standHours)
}
}
}
Exploring MusicKit and Apple Music API
Unlock the full power of MusicKit & Apple Music APIs in your apps with the best guide! Use code musickit-blog for a limited-time 35% discount!