Compare commits

...

1 Commits

Author SHA1 Message Date
Roberto Viola
9845cb2cb0 new metrics but now are only avaiable for outdoor workouts
runningStrideLength
A quantity sample type that measures the distance covered by a single step while running.
iOS 16.0+
iPadOS 16.0+
macOS 13.0+ Beta
Mac Catalyst 16.0+ Beta
watchOS 9.0+
Declaration
static let runningStrideLength: HKQuantityTypeIdentifier
Discussion
These samples use length units (described in HKUnit) and measure discrete values (described in HKQuantityAggregationStyle). During outdoor running workouts, the system automatically records running stride samples on Apple Watch SE and Series 6 and later.

https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/3929732-runningstridelength/
2022-09-13 14:50:13 +02:00
2 changed files with 152 additions and 9 deletions

View File

@@ -90,6 +90,27 @@ extension MainController {
}
extension MainController: WorkoutTrackingDelegate {
func didReceiveHealthKitStrideLength(_ strideLength: Double) {
if self.sport == 1 {
WatchKitConnection.shared.sendMessage(message: ["strideLength":
"\(strideLength)" as AnyObject])
}
}
func didReceiveHealthKitGroundTime(_ groundTime: Double) {
if self.sport == 1 {
WatchKitConnection.shared.sendMessage(message: ["groundTime":
"\(groundTime)" as AnyObject])
}
}
func didReceiveHealthKitVerticalOscillation(_ verticalOscillation: Double) {
if self.sport == 1 {
WatchKitConnection.shared.sendMessage(message: ["verticalOscillation":
"\(verticalOscillation)" as AnyObject])
}
}
func didReceiveHealthKitDistanceCycling(_ distanceCycling: Double) {
@@ -108,6 +129,10 @@ extension MainController: WorkoutTrackingDelegate {
self.distanceLabel.setText("Distance \(Double(WorkoutTracking.distance))")
self.caloriesLabel.setText("KCal \(Int(WorkoutTracking.kcal))")
//WorkoutTracking.cadenceSteps = pedometer.
WorkoutTracking.shared.fetchGroundContactTime()
WorkoutTracking.shared.fetchVerticalOscillation()
WorkoutTracking.shared.fetchStrideLength()
}
func didReceiveHealthKitStepCounts(_ stepCounts: Double) {

View File

@@ -12,6 +12,9 @@ import HealthKit
protocol WorkoutTrackingDelegate: class {
func didReceiveHealthKitHeartRate(_ heartRate: Double)
func didReceiveHealthKitStepCounts(_ stepCounts: Double)
func didReceiveHealthKitStrideLength(_ strideLength: Double)
func didReceiveHealthKitGroundTime(_ groundTime: Double)
func didReceiveHealthKitVerticalOscillation(_ verticalOscillation: Double)
func didReceiveHealthKitStepCadence(_ stepCadence: Double)
func didReceiveHealthKitDistanceCycling(_ distanceCycling: Double)
func didReceiveHealthKitActiveEnergyBurned(_ activeEnergyBurned: Double)
@@ -22,6 +25,9 @@ protocol WorkoutTrackingProtocol {
func startWorkOut()
func stopWorkOut()
func fetchStepCounts()
func fetchVerticalOscillation()
func fetchGroundContactTime()
func fetchStrideLength()
}
class WorkoutTracking: NSObject {
@@ -138,22 +144,52 @@ extension WorkoutTracking {
extension WorkoutTracking: WorkoutTrackingProtocol {
static func authorizeHealthKit() {
if HKHealthStore.isHealthDataAvailable() {
let infoToRead = Set([
HKSampleType.quantityType(forIdentifier: .stepCount)!,
HKSampleType.quantityType(forIdentifier: .heartRate)!,
/*HKSampleType.quantityType(forIdentifier: .distanceCycling)!,
HKSampleType.quantityType(forIdentifier: .activeEnergyBurned)!,*/
HKSampleType.workoutType()
])
var infoToRead: Set<HKSampleType>
if #available(watchOSApplicationExtension 9.0, *) {
infoToRead = Set([
HKSampleType.quantityType(forIdentifier: .stepCount)!,
HKSampleType.quantityType(forIdentifier: .heartRate)!,
/*HKSampleType.quantityType(forIdentifier: .distanceCycling)!,
HKSampleType.quantityType(forIdentifier: .activeEnergyBurned)!,*/
HKSampleType.quantityType(forIdentifier: .runningGroundContactTime)!,
HKSampleType.quantityType(forIdentifier: .runningStrideLength)!,
HKSampleType.quantityType(forIdentifier: .runningVerticalOscillation)!,
HKSampleType.workoutType()
])
} else {
infoToRead = Set([
HKSampleType.quantityType(forIdentifier: .stepCount)!,
HKSampleType.quantityType(forIdentifier: .heartRate)!,
/*HKSampleType.quantityType(forIdentifier: .distanceCycling)!,
HKSampleType.quantityType(forIdentifier: .activeEnergyBurned)!,*/
HKSampleType.workoutType()
])
}
let infoToShare = Set([
var infoToShare: Set<HKSampleType>
if #available(watchOSApplicationExtension 9.0, *) {
infoToShare = Set([
HKSampleType.quantityType(forIdentifier: .stepCount)!,
HKSampleType.quantityType(forIdentifier: .heartRate)!,
HKSampleType.quantityType(forIdentifier: .distanceCycling)!,
HKSampleType.quantityType(forIdentifier: .distanceWalkingRunning)!,
HKSampleType.quantityType(forIdentifier: .activeEnergyBurned)!,
HKSampleType.quantityType(forIdentifier: .runningGroundContactTime)!,
HKSampleType.quantityType(forIdentifier: .runningStrideLength)!,
HKSampleType.quantityType(forIdentifier: .runningVerticalOscillation)!,
HKSampleType.workoutType()
])
} else {
// Fallback on earlier versions
infoToShare = Set([
HKSampleType.quantityType(forIdentifier: .stepCount)!,
HKSampleType.quantityType(forIdentifier: .heartRate)!,
HKSampleType.quantityType(forIdentifier: .distanceCycling)!,
HKSampleType.quantityType(forIdentifier: .distanceWalkingRunning)!,
HKSampleType.quantityType(forIdentifier: .activeEnergyBurned)!,
HKSampleType.quantityType(forIdentifier: .activeEnergyBurned)!,
HKSampleType.workoutType()
])
}
HKHealthStore().requestAuthorization(toShare: infoToShare, read: infoToRead) { (success, error) in
if success {
@@ -269,6 +305,88 @@ extension WorkoutTracking: WorkoutTrackingProtocol {
}
healthStore.execute(query)
}
func fetchStrideLength() {
if #available(watchOSApplicationExtension 9.0, *) {
guard let stepCounts = HKQuantityType.quantityType(forIdentifier: .runningStrideLength) else {
return
}
let startOfDay = Calendar.current.startOfDay(for: workoutSession.startDate ?? Date())
let predicate = HKQuery.predicateForSamples(withStart: startOfDay, end: Date(), options: .strictStartDate)
let query = HKStatisticsQuery(quantityType: stepCounts, quantitySamplePredicate: predicate, options: .mostRecent) { [weak self] (_, result, error) in
guard let weakSelf = self else {
return
}
guard let result = result else {
print("Failed to fetch stride length")
return
}
result.mostRecentQuantity()
let r = result.mostRecentQuantity()?.doubleValue(for: .meter()) ?? 0
print("stride length \(r)")
weakSelf.delegate?.didReceiveHealthKitStrideLength(r)
}
healthStore.execute(query)
} else {
// Fallback on earlier versions
}
}
func fetchGroundContactTime() {
if #available(watchOSApplicationExtension 9.0, *) {
guard let stepCounts = HKQuantityType.quantityType(forIdentifier: .runningGroundContactTime) else {
return
}
let startOfDay = Calendar.current.startOfDay(for: workoutSession.startDate ?? Date())
let predicate = HKQuery.predicateForSamples(withStart: startOfDay, end: Date(), options: .strictStartDate)
let query = HKStatisticsQuery(quantityType: stepCounts, quantitySamplePredicate: predicate, options: .mostRecent) { [weak self] (_, result, error) in
guard let weakSelf = self else {
return
}
guard let result = result else {
print("Failed to fetch contact time")
return
}
let r = result.mostRecentQuantity()?.doubleValue(for: .second()) ?? 0
print("ground contact time \(r)")
weakSelf.delegate?.didReceiveHealthKitGroundTime(r)
}
healthStore.execute(query)
} else {
// Fallback on earlier versions
}
}
func fetchVerticalOscillation() {
if #available(watchOSApplicationExtension 9.0, *) {
guard let stepCounts = HKQuantityType.quantityType(forIdentifier: .runningVerticalOscillation) else {
return
}
let startOfDay = Calendar.current.startOfDay(for: workoutSession.startDate ?? Date())
let predicate = HKQuery.predicateForSamples(withStart: startOfDay, end: Date(), options: .strictStartDate)
let query = HKStatisticsQuery(quantityType: stepCounts, quantitySamplePredicate: predicate, options: .mostRecent) { [weak self] (_, result, error) in
guard let weakSelf = self else {
return
}
guard let result = result else {
print("Failed to fetch vertical oscillation")
return
}
let r = result.mostRecentQuantity()?.doubleValue(for: .meter()) ?? 0
print("vertical oscillation \(r)")
weakSelf.delegate?.didReceiveHealthKitVerticalOscillation(r)
}
healthStore.execute(query)
} else {
// Fallback on earlier versions
}
}
}
extension WorkoutTracking: HKLiveWorkoutBuilderDelegate {