SwiftUI×HealthKitでiOSデータ入門(後編)

# HealthKitデータ取得 & Firebase 編

ここまで SwiftUI のキャチアップをしつつ[前編](https://qiita.com/_kenken82/private/22df88d1b148739837ea)で環境を構築し，[中編](https://qiita.com/_kenken82/private/f9de71e58be5b57f3634)で HealthKit を利用可能にしました．今回は実際に HealthKit で歩数データを取得します．

## HealthKitで歩数データを取得
前回の記事で権限は得られたのでデータの読み出しが可能となっているはずです．次にデータを取得していきます．少しややこしいです．細かいところは順次付け足していくとして，とりいそぎで書き加えたコードだけを載せます．

DataCollection.swift を編集していきます．body より前に以下の変数を定義していきます．

```Swift
let type = HKObjectType.quantityType(forIdentifier: .stepCount)!  // allTypeとは別にtypeを定義
    var calendar = Calendar.current  // カレンダーを取得
```
このように書きます(追加したのは下2行)．

```DataCollection.swift
struct DataCollection: View {
    // @Stateを使ってUIの状態と同期をとる
    @State var labelText = "Tap Here"
    @State var flag = false
    let healthStore = HKHealthStore()  // HealthKitのデータを格納するHealthStoreを定義
    // アクセス許可が欲しいデータタイプを指定
    let allTypes = Set([HKObjectType.quantityType(forIdentifier: .stepCount)!])  //今回は歩数のみ
    
    // 以下を追加
    let type = HKObjectType.quantityType(forIdentifier: .stepCount)!  // allTypeとは別にtypeを定義
    var calendar = Calendar.current  // カレンダーを取得
```
さらにボタンがタップされた時の処理を以下のように書き換えます．ここでは「昨日から今日まで」に歩いた歩数を取得します．

```DataCollection.swift
// ボタンがタップされた時
// もしHealthKitが利用可能なら
if HKHealthStore.isHealthDataAvailable() {
    self.labelText = "HealthKit Available"

    self.healthStore.requestAuthorization(toShare: nil, read: self.allTypes) { (success, error) in}
        
        // 以下を追加
        let date = Date()  // 今日の日付を取得
        let yesterday = self.calendar.date(byAdding: .day, value: -1, to: date)  // "昨日"は上で定義したカレンダーを使って計算する
        
        // 取得するデータの開始(きのう)と終わり(きょう)を入れる
        let predicate = HKQuery.predicateForSamples(withStart: yesterday, end: date)
        var step = 0.0  // 結果を格納するための変数

        // クエリを作る
       let query = HKStatisticsQuery(quantityType: self.type, quantitySamplePredicate: predicate, options:.cumulativeSum){query, result, error in
       let query_result = result?.sumQuantity() as Any
       step = (query_result as AnyObject).doubleValue(for: HKUnit.count())  // HKQuantity型をdoubleに変換
       print(step)  // コンソールに出力
       self.labelText = String(step) + "歩" // 文字列に変換してデバイスに表示
```

これで間違いがなければビルドが通り，コンソールに歩数データが表示されるはず．
![Screen Shot 2019-12-14 at 20.03.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/76122/b052034d-4690-fb62-2470-c3b3d18f9066.png)

また，デバイスのボタンをタップすると歩数が表示されるはず．
<img width="375" alt="IMG_8263.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/76122/3b9f3108-819a-cd74-a29d-f8933f3b123e.png">

ここまでで，iPhone からデータを取得することに成功しました！

## Firebaseへデータを格納
ここからは，先ほど取得したデータをデータベースへ格納します．他のアプリと連携できるように [Firebase](https://firebase.google.com/?hl=ja) の [Firestore](https://firebase.google.com/docs/firestore?hl=ja) にデータを格納します．当初 Realm を使う予定でしたがハッカソンの戦略上，Firebase へ変更しました．

### Firebase (Firestore)
Firebase の環境構築は[公式](https://firebase.google.com/docs/firestore/quickstart?hl=ja)のインストラクションがわかりやすいのでここでは省略します．[「Firebase を iOS プロジェクトに追加する」方法](https://firebase.google.com/docs/ios/setup?hl=ja)をみながら設定をしてください．この設定が済んでいる前提でデータを送るところをやっていきます．

まずは以下の3つのコード

```Swift
import Firebase
var window: UIWindow?
FirebaseApp.configure()
```
をAppDelegate.swift に追記します．以下のように書き変えていきます．

```AppDelegate.swift
import UIKit
import Firebase  // 追加した行

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow? // 追加した行
    func application(_ application: UIApplication, didFinishLaunchingWithOptions 
    launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // Override point for customization after application launch.

        // Firebase
        FirebaseApp.configure()  // 追加した行
        return true
    }
```

そして DataCollection.swift のボタンがタップされた時の処理を書いた部分に以下の処理を追加します．

```DataCollection.swift
<略>
 // クエリを作る
let query = HKStatisticsQuery(quantityType: self.type, quantitySamplePredicate: predicate, options:.cumulativeSum){
    query, result, error in
    let query_result = result?.sumQuantity() as Any
    step = (query_result as AnyObject).doubleValue(for: HKUnit.count())  // HKQuantity型をdoubleに変換
    print(step)  // コンソールに出力
    self.labelText = String(step) + "歩" // デバイスに表示
                            
    // ここからが追加したFirebaseの処理
    let db = Firestore.firestore()
    var ref: DocumentReference? = nil
    ref = db.collection("Health").addDocument(data: [
        "歩数": step
    ]) { err in
        if let err = err {
            print("Error adding document: \(err)")
        } else {
            print("Document added with ID: \(ref!.documentID)")
        }
       }
     }
     self.healthStore.execute(query)         
}else{
<略>
```

これで問題なければ，ボタンを押すたびにデータが FireStore にも格納されているはずです．
![Screen Shot 2019-12-15 at 0.52.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/76122/bea1a13c-94b8-3b47-b320-2286f947648c.png)

実験で作った余分なコレクションも見えていますが，こんな感じでうまくいきました！

## まとめ
ここまでSwift×HealthKitでiOSデータ入門の [前編](https://qiita.com/_kenken82/private/22df88d1b148739837ea)，[中編](https://qiita.com/_kenken82/private/f9de71e58be5b57f3634)，[後編](https://qiita.com/_kenken82/private/8201f6e7b6a07c61b8ff) を通してざっくり

1. Swift (SwiftUI) のキャッチアップとして画面遷移とボタンの実装
2. HealthKit からのデータの取得
3. Firebase へのデータの格納

の3つを行いました．iOS開発どころか Xcode や Swift, HealthKit を触るのも初めてだったので説明不足や理解が不十分な点がまだまだあります．このあたりは今後も引き続きキャッチアップとアップデートを行っていこうと考えています．もし気づいた点などあればコメントなどいただけると大変助かります．

以上，**SwiftUI×HealthKitでiOSデータ入門** でした．