📱

iOSで歩数を取得する方法[Swift]

2022/12/11に公開

はじめに

業務ではWebシステムの開発していますが、趣味でiOSアプリを個人開発しています。
個人開発中のアプリで歩数情報を取得する必要があり、方法の調査をしていたので備忘を兼ねてiOSで歩数を取得する方法について書きます。

iOSで歩数を取得する手段

iOSで歩数を取得する手段は2つあります。

  1. CoreMotionフレームワークのCMPedometer を使用する
  2. HealthKitフレームワークを使用する

それぞれ特徴があるので、どちらの方法を採用するかはアプリの用途によります。

CoreMotionのCMPedometerで取得する

端末に搭載されているモーションコプロセッサが計測した歩数情報を取得します。

  • 特徴
    • リアルタイムに歩数を取得できる
    • HealthKitより気にすることが少なく実装が簡単
    • 直近7日より前の歩数は取得できない
    • 取得できるのはアプリが起動している端末の情報のみ

リアルタイムに歩数を取得する

let pedometer = CMPedometer()
pedometer.startUpdates(from: nowDate) { (data, error) in
    guard error == nil else {
	return
    }
    print(data?.numberOfSteps)
}
  • 一歩毎ではなく1~2秒間隔くらいで、fromに指定した開始日時以降の合計歩数が取得できます。

過去の歩数を期間を指定して取得する

let pedometer = CMPedometer()
pedometer.queryPedometerData(from: startDate, to: endDate) { (data, error) in
    guard error == nil else {
	return
    }
    print(data?.numberOfSteps)
}
  • 開始日時に大昔の日時を指定しても、取得できるのは直近7日分です

HealthKitから取得する

Appleの「ヘルスケア」アプリにて収集されている色々なデータの中から歩数情報を取得します。

  • 特徴
    • ヘルスケアに収集されている情報であれば、過去すべて取得できる
    • iPhoneとApple Watch 両方の歩数を取得できるが、取得の仕方を誤ると期待値と大きく異なる結果になってしまう
    • ヘルスケアへのデータ収集にタイムラグがあり、リアルタイムな歩数取得はできない

HKStatisticsQueryDescriptor で 期間を指定して取得する

HKStatisticsQuery は 統計値を計算するクエリです。
HKStatisticsQueryDescriptor は HKStatisticsQueryの Swift Concurrency(async/await)サポート版です。
これを使用することでよい感じに歩数取得ができます。

let healthKitStore = HKHealthStore()
let quantityType = HKSampleType.quantityType(forIdentifier: .stepCount)!
let periodPredicate = HKQuery.predicateForSamples(
    withStart: startDate,
    end: endDate
)
let predicate = HKSamplePredicate.quantitySample(
    type: quantityType,
    predicate: periodPredicate
)
let descriptor = HKStatisticsQueryDescriptor(
    predicate: predicate,
    options: .cumulativeSum // 合計値
)
do {
    let sum = try await descriptor.result(for: healthKitStore)?
        .sumQuantity()?
        .doubleValue(for: .count())
    print(sum)
} catch {
    // 例外発生
}

HKSampleQueryDescriptor で 期間を指定して取得する(非推奨)

let healthKitStore = HKHealthStore()
let quantityType = HKSampleType.quantityType(forIdentifier: .stepCount)!
let periodPredicate = HKQuery.predicateForSamples(
    withStart: startDate,
    end: endDate
)
let predicate = HKSamplePredicate.quantitySample(
    type: quantityType,
    predicate: periodPredicate
)
let descriptor = HKSampleQueryDescriptor(
    predicates: [predicate],
    sortDescriptors: []
)
do {
    let results = try await descriptor.result(for: healthKitStore)
    let sum = results.reduce(0) {$0 + $1.quantity.doubleValue(for: .count())}
    print(sum)
} catch {
    // 例外発生
}

おわりに

iOSでの代表的な歩数取得方法を書かせていただきました。
Swift Concurrency版を使用した例はあまり見たことがなかったので参考になれば幸いです。
ここまで読んでいただきありがとうございました。

参考資料

Core Motion - Apple Developer Documentation
HealthKit - Apple Developer Documentation
iOSで正しく歩数を取得する - Qiita

BABY JOB  テックブログ

Discussion