iOSの歩数取得方法の選び方

## iOSの歩数取得方法の選び方

### どうやって歩数取得するのか

#### 方法は3つ
- CoreMotionフレームワークの[CMPedometer](https://developer.apple.com/documentation/coremotion/cmpedometer)を使用する
- HealthKitフレームワークの[HKHealthStore](https://developer.apple.com/documentation/healthkit/hkhealthstore)を使用する
- CoreMotionフレームワークの[CMMotionManager](https://developer.apple.com/documentation/coremotion/cmmotionmanager)を使用する

---

#### CMPedometerの方法

CoreMotionフレームワークにCMPedometerクラスがあるので、これのstartUpdates（）を使用すると[CMPedometerData](https://developer.apple.com/documentation/coremotion/cmpedometerdata)というのが取れる。

これの中に歩数データがあります。

初回のみ許可ダイアログが出ます

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1127006/9a8a2c69-1cfd-476b-9358-c6fd8d36e8b0.png" width="320px">

```swift
let pedometer = CMPedometer()
pedometer.startUpdates(from: nowDate) { (data, error) in // fromに開始日を設定して取得できる（7日前まで可能）
    guard error == nil else {
	return
    }
    print(data?.numberOfSteps)
}

```
期間を指定して取得も可能

```swift
let pedometer = CMPedometer()
pedometer.queryPedometerData(from: startDate, to: endDate) { (data, error) in
    guard error == nil else {
	return
    }
    print(data?.numberOfSteps)
}
```

---

#### HKHealthStoreの方法

いろんな書き方があるがここでは一つだけ紹介

HKHealthStoreの[HKStatisticsCollectionQuery](https://developer.apple.com/documentation/healthkit/hkstatisticscollectionquery)を作成してある程度フィルターしたデータを取得する方法

まずは許可が必要でHKObjectType.quantityType（）の引数の[HKQuantityTypeIdentifier](https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier)で指定できる。（歩数ならstepCount、移動距離ならdistanceWalkingRunningなど）



```swift
    /// 認証許可
    private func usagePermission() {
        
        if HKHealthStore.isHealthDataAvailable() {
            print("対応")
        } else {
            print("非対応")
        }
        
        let dictionaryData = [
            HKObjectType.quantityType(forIdentifier: .stepCount)!
        ]
        
        let readDataTypes = Set(dictionaryData)
        HKHealthStore().requestAuthorization(toShare: nil, read: readDataTypes) { success, _ in
            if success {
                self.fetchSteps()
            }
        }
    }
```

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1127006/cd075dfe-405f-4886-afeb-82119a0a7e6c.png" width="320px"> <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1127006/ed63c6f7-4928-4b45-9816-0ce00147f05b.png" width="320px">

- quantityType = データタイプの統計を取得するか（歩数、血圧、脈拍など）
- quantitySamplePredicate = フィルタリング条件（いつからいつまでのデータを取得するか）
- options = 統計の種類(平均、合算、最小など)
- anchorDate =　統計情報の集計を開始する基準日
- intervalComponents = 統計情報の集計間隔（日毎、週毎、月毎、年毎）

```swift
func fetchSteps(completion: @escaping (HKStatisticsCollection?) -> Void) {
        // パラメータの値の記述は割愛してます
	let query = HKStatisticsCollectionQuery(
	    quantityType: stepType,
	    quantitySamplePredicate: predicate,
	    options: .cumulativeSum,
	    anchorDate: anchorDate,
	    intervalComponents: daily
	)

	query.initialResultsHandler = { query, statisticsCollection, error in
	    completion(statisticsCollection)
	}

	HKHealthStore().execute (query)
}
```

---

#### CMMotionManagerの方法
CMMotionManagerの加速度センサーで取得したデータを取得できるので、それを自前で歩数に変換する方法

計算は自分でやる必要があるので詳細は割愛

[参考](https://github.com/tsuboyan/RealtimeStepCounterForiOS)

---

### それぞれの特色
- CMPedometer
   - 歩数の反映が２番目に早い（10秒以内）
   - capablity追加の必要なし
   - 簡単に実装できる
- HKHealthStore
   - 歩数の反映は遅い（10秒以上）
   - 取れるデータが幅広い（血圧、脈拍なども可能）
 
- CMMotionManager
   - 歩数の反映はリアルタイムだが、歩数データへの変換は自分でやる必要がある
   - バッテリーの消耗は激しいと思う

---

### どう選択するか
- ただの歩数計　＝　CMPedometer or HKHealthStore
- リアルタイムで歩数反映したい　＝　CMPedometer　or CMMotionManager
- １週間以上の期間の健康管理アプリとか　＝　HKHealthStore
- １週間のデータしか表示しない　= CMPedometer

もちろん組み合わせてもいいと思います！

ex: 
- 歩数データは早く反映したいのでCMPedometerで、それ以外の健康データはHKHealthStoreからとか

### 備考
- ヘルスケア連携　（HKHealthStore）は許可ダイアログが一回しか出せないので、確実にユーザーに歩数を取らせたいときはCMPedometerの方が良いかも
   - CMPedometerは設定アプリ内の「モーションとフィットネス」へ遷移できるが、ヘルスケアはできない（ユーザーに設定アプリかヘルスケアアプリで設定してもらう必要がある）

### 参考
- https://zenn.dev/ueshun/scraps/90fbb43a2bb3d7
- https://zenn.dev/toaster/articles/5b63ba6038a7fc