🩺

【iOS】Workoutを運動項目毎に分割する

2024/06/16に公開

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のフォローをよろしくお願いいたします。

https://sites.google.com/view/muranakar

個人でアプリを作成しています。良かったら覗いてみてください。

参考資料

https://developer.apple.com/documentation/healthkit/workouts_and_activity_rings/dividing_a_healthkit_workout_into_activities

Discussion