【iOS】Workoutを運動項目毎に分割する
HealthKit を使用してマルチスポーツやインターバルトレーニングを個別の運動項目(アクティビティ)に分割する方法について説明します。例えば、トライアスロンなどのマルチスポーツでは、水泳、自転車、ランニングの各部分を個別のアクティビティとして作成できます。同様に、インターバルトレーニングではアクティブな期間と休憩期間を分割することが可能です。
HKWorkoutActivityの使用
HKWorkoutActivity
を使用して実装します。このオブジェクトは主に以下の2つのケースで使用されます。
マルチスポーツ
HKWorkoutActivityType.swimBikeRun
のアクティビティタイプを持つワークアウトでは
HKWorkoutActivityType.swimming
HKWorkoutActivityType.cycling
HKWorkoutActivityType.running
上記のHKWorkoutActivity
を使用します。アクティビティの間を示すには HKWorkoutActivityType.transition
を使用できます。
インターバルトレーニング
インターバルトレーニングのアクティビティを表すために HKWorkoutActivity
を使用します。インターバルワークアウトは HKWorkoutActivityType
で作成できますが、同じアクティビティタイプを使用する必要があります。以下に詳細を記載しています。
ワークアウトの移行・休憩
マルチスポーツでは、HKWorkoutActivityType.transitionタイプを使用して、アクティビティ間の移行を記録できます。インターバルの場合、2つの選択肢があります。
- 休息時間にはワークアウトと同じアクティビティタイプを使用する
- 運動中インターバルであるか、休息インターバルであるかを示すカスタムメタデータを追加する
インターバルのデータをどのように記録するかは、アプリのニーズとインターバルの種類によって異なります。速いペースと遅いペースを交互に繰り返すワークアウトを記録している場合、すべてのインターバルを記録すべきです。しかし、インターバルが運動と休息を交互に繰り返す場合、休息インターバルは空白のままにしておくとよいです。
アクティビティをワークアウトセッションに追加する方法
ワークアウトセッションの作成
まず、セッションを作成し、WorkoutBuilderを使用してデータ収集を開始します。
// マルチスポーツワークアウトの設定を作成
let configuration = HKWorkoutConfiguration()
configuration.activityType = .swimBikeRun
configuration.locationType = .outdoor
// ワークアウトセッションを作成
session = try HKWorkoutSession(healthStore: store, configuration: configuration)
// セッションとワークアウトビルダーを開始
let startDate = Date()
session.startActivity(with: startDate)
workoutBuilder = session.associatedWorkoutBuilder()
// ワークアウトビルダーのデータソースを設定
workoutBuilder.dataSource = HKLiveWorkoutDataSource(healthStore: store, workoutConfiguration: configuration)
// データ収集を開始
try await workoutBuilder.beginCollection(at: startDate)
アクティビティの開始と終了
アクティビティが始まると、新しいHKWorkoutConfiguration
を作成し、セッションの beginNewActivity(configuration:date:metadata:)
メソッドを使用してアクティビティを開始します。
// 水泳アクティビティを開始
let swimmingConfiguration = HKWorkoutConfiguration()
swimmingConfiguration.activityType = .swimming
swimmingConfiguration.locationType = .outdoor
swimmingConfiguration.swimmingLocationType = .openWater
// アクティビティを開始
session.beginNewActivity(configuration: swimmingConfiguration, date: Date(), metadata: nil)
// アクティビティを終了
session.endCurrentActivity(on: Date())
アクティビティ間の移行を追跡するためには、HKWorkoutActivityType.transition
を使用します。
// アクティビティ間の移行を明示的に追跡
let transitionConfiguration = HKWorkoutConfiguration()
transitionConfiguration.activityType = .transition
transitionConfiguration.locationType = .outdoor
// アクティビティを開始
session.beginNewActivity(configuration: transitionConfiguration, date: Date(), metadata: nil)
ワークアウトセッションの終了
全体のワークアウトセッションが終了すると、セッションの end()
メソッドを呼び出します。これにより、現在のアクティビティも終了します。その後、ワークアウトビルダーの finishWorkout(completion:)
メソッドを呼び出して、ワークアウトを HealthKitStoreに保存します。
// セッションの終了は現在のアクティビティも終了
session.end()
// ワークアウトを完了して保存
let workout = try await workoutBuilder.finishWorkout()
// ワークアウトの情報を表示
print(workout)
データ収集の有効化と無効化
アクティビティを開始すると、データソースは自動的にAppleWatchから関連データの収集を開始します。必要に応じて、特定のデータタイプの収集を手動で有効または無効にできます。
guard let dataSource = session.associatedWorkoutBuilder().dataSource else {
print("*** No data source found! ***")
return
}
let respiratoryRate = HKQuantityType(.respiratoryRate)
// 呼吸数の収集を有効化
dataSource.enableCollection(for: respiratoryRate, predicate: nil)
// 呼吸数の収集を無効化
dataSource.disableCollection(for: respiratoryRate)
ワークアウトアクティビティのクエリ
特定の条件に一致するアクティビティを持つワークアウトを呼び出すには、まず HKQuery
クラスの predicateForWorkoutActivities
メソッドを使用してアクティビティの条件を作成します。
// 150 bpm を超える平均心拍数の条件値・条件を作成
let highHeartRate = HKQuantity(unit: .count(), doubleValue: 150.0)
let heartRateType = HKQuantityType(.heartRate)
let heartRatePredicate = HKQuery.predicateForWorkoutActivities(operatorType: .greaterThan, quantityType: heartRateType, averageQuantity: highHeartRate)
// ワークアウトの条件内に、アクティビティの条件をラップ
let workoutPredicate = HKQuery.predicateForWorkouts(activityPredicate: heartRatePredicate)
let query = HKSampleQueryDescriptor(predicates: [.workout(workoutPredicate)], sortDescriptors: [])
// クエリを実行する
let matchingWorkouts = try await query.result(for: store)
この例では、平均心拍数が150 bpmを超えるアクティビティを持つすべてのワークアウトを返します。ワークアウトの workoutActivities
を使用して、ワークアウトに関連するアクティビティにアクセスできます。
最後に
間違い・気になる部分がありましたら、コメントいただけると大変うれしいです。
良かったと思ったら記事へのいいね、Xのフォローをよろしくお願いいたします。
個人でアプリを作成しています。良かったら覗いてみてください。
参考資料
Discussion