1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

iOS #2Advent Calendar 2019

Day 6

HealthKitで水泳の各ラップのストローク数が取りたい

Last updated at Posted at 2019-12-05

この記事はiOS #2 Advent Calendar 2019の6日目の記事です。

はじめに

Apple Watchで水泳のワークアウトが測定できるの知ってました?
IMG_4193.PNG

ワークアウトアプリにプールスイミングがあるので、これを実行しながらプールで泳げば、測定できます。
測定結果はApple WatchとペアリングしているiPhoneのアクティビティアプリで確認できます。
サンプルデータですが、このように表示されます。
IMG_4195.jpg

ラップ数や泳いでいるときの泳法も測定できていて、すごい! てなるのですが、
このアプリでは各ラップのストローク数は確認できません。
HealthKitで取れるだろう、と思ってやってみました。

アプリでHealthKitが使えるようにする

公式ドキュメントを参照して、手順通りに行います。
プロジェクトファイルとInfo.plistを編集します。

水泳のワークアウトデータを取ってみる

サンプルコード

.swift
import HealthKit

let healthStore = HKHealthStore()

let readDataTypes: Set<HKObjectType> = [HKWorkoutType.workoutType()]

healthStore.requestAuthorization(
    toShare: nil,
    read: readDataTypes,
    completion: {(success, error) in
        if success {
            let predicate = HKQuery.predicateForWorkouts(with: HKWorkoutActivityType.swimming)
            let sortDescriptor = NSSortDescriptor(key: HKSampleSortIdentifierStartDate, ascending: false)
            let sampleQuery = HKSampleQuery(
                sampleType: HKObjectType.workoutType(),
                predicate: predicate,
                limit: HKObjectQueryNoLimit,
                sortDescriptors: [sortDescriptor],
                resultsHandler: {(_, results, error) in
                    if error == nil {
                        let workouts = results as! [HKWorkout]
                        if let workout = workouts.first {
                            print(workout.workoutEvents)
                        }
                    }
            })

            healthStore.execute(sampleQuery)
        }
})

このコードをざっと説明すると、

  1. ヘルスケアデータからワークアウトを取る許可を取得する
  2. swimmingのワークアウトを最新から順に取得する
  3. 最新のワークアウトのworkoutEventsを出力する
    になります。
    print文で出力したworkoutEventsから、サンプルとして一つを抜き出してみると
HKWorkoutEventTypeLap, <_NSConcreteDateInterval: 0x28300eb40> (Start Date) 2019-10-24 10:56:05 +0000 + (Duration) 6.520985 seconds = (End Date) 2019-10-24 10:56:11 +0000 {
    HKSwimmingStrokeStyle = 5;

水泳のワークアウトの1ラップのデータと読み取れますが、ストローク数と思われるデータはありません。
公式のドキュメントを参照すると分かるのですが、HKWorkoutEventクラスにはストローク数と思われるものはありません。
また、HKWorkoutクラスにtotalSwimmingStrokeCountというものはあるのですが、これはワークアウト単位のものであって、各ラップのストローク数ではありません。
別のアプローチが必要です。

そこで、ヘルスケアデータには水泳のストローク数というタイプがあるので、そこから取得しました。

水泳のストローク数から取得する

.swift
let readDataTypes: Set<HKObjectType> = [HKWorkoutType.workoutType(),
                                        HKObjectType.quantityType(forIdentifier: .swimmingStrokeCount)!]

に書き換えて、先ほど取得したworkoutEventsを使って

.swift
let type = HKObjectType.quantityType(forIdentifier: .swimmingStrokeCount)!

for (index, workoutEvent) in workoutEvents.enumerated()  {
    // workoutEventのtypeにはlap, segment, pauseなどがあります
    if workoutEvent.type == .lap {
        let predicate = HKQuery.predicateForSamples(withStart: workoutEvent.dateInterval.start, end: workoutEvent.dateInterval.end, options: .strictStartDate)
        let query = HKStatisticsQuery(quantityType: type,
                                      quantitySamplePredicate: predicate,
                                      options: [.cumulativeSum]) { (_, statistic, error) in
                                          guard let statistic = statistic, error == nil else {
                                              return
                                          }
                                          let sum = statistic.sumQuantity()?.doubleValue(for: HKUnit.count()) ?? 0
                                          print("stroke:\(sum) index:\(index)")
        }

        healthStore.execute(query)
    }
}

水泳のストローク数の保存データに対して、各workoutEventの開始日時と終了日時を指定して、クエリーを投げています。
print文の箇所は非同期に実行されるため、インデックスも追加して、workoutEventsの何番目か分かるようにしました。

stroke:8.0 index:1
stroke:3.0 index:2
stroke:15.0 index:3
stroke:11.0 index:4
stroke:11.0 index:5
stroke:6.0 index:6
stroke:11.0 index:7
stroke:10.0 index:9
stroke:7.0 index:10
stroke:13.0 index:12
stroke:7.0 index:15
stroke:10.0 index:13
stroke:4.0 index:16
stroke:11.0 index:14

出力はworkoutEventsの順番通りではありませんが、これでストローク数を取得できました。

HKStatisticsQueryの公式ドキュメント以外に参考になる事例を見つけられなかったので、
より良いやり方や、同じようなことを試みたことがあれば、コメント下さい。

サンプルコードはこちらにも上げました。

ありがとうございました。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?