HealthKitでcyclingの時速は直接取得できないぞ!

結論

HealthKit経由で取得したワークアウト(HKWorkout) から時速を取得するには、 totalDistance(HKQuantity)duration(TimeInterval) を使って算出する必要がある。

let distance = workout.totalDistance!.kilometers()
let averageSpeed = distance / ((Double)(Int(timeInterval)) / 3600)

extension HKQuantity {
    func kilometers() -> Double {
        return self.doubleValue(for: .meter()) / 1000
    }
}

開発環境

> xcodebuild -version
Xcode 13.3
Build version 13E113

モチベーション

最近趣味でApple Watchで計測したサイクリングのワークアウトのデータを集計するSwiftUI製アプリを作っている。

github.com

現状の問題として、1回のワークアウトの合計走行距離や時間はHealthKit経由で取得できたが時速を取得できない。時速を取得したい。

勘違い

Apple公式のフィットネスのアプリでワークアウトを見ると、平均速度の項目があるので合計走行距離(totalDistance(HKQuantity)などと同様にHealthKit経由で取得できると考えていた。
しかし、いくらドキュメントを彷徨っても該当するプロパティが存在しない。
一番近そうなHKMetadataKeyAverageSpeedはサイクリングのワークアウトのmetaDataにKeyが存在せず、権限周りに問題があるかと思ったが結果として取得できなかった。

結果として、結論にも書いてあるが合計走行距離とワークアウトにかかった時間は既に取得できていたので、それらを使って計算させればいいだけのことだった。(ということに気づくのに時間がかかった)

コード

let distance = workout.totalDistance!.kilometers()

// TimeIntervalの単位は秒のため時速を計算するために時間(hour)に直す
let averageSpeed = distance / ((Double)(Int(timeInterval)) / 3600)

extension HKQuantity {
    // 標準でHKQuantityをメートルに変換する処理があるので利用。km/hを計算したいのでmをkmに変換する処理を追加。
    func kilometers() -> Double {
        return self.doubleValue(for: .meter()) / 1000
    }
}

TimeIntervalはDoubleのtypealiasなんだね。知らなんだ。

参考