米国ではWatch OS 5.1.2よりECG(心電計)が使えるようになったみたいですね。
早く、日本でも使えるようになってほしいものです。(薬機法とか色々あるので、大変ですが。。。)
ちなみに、ECGが大きくインパクトを与える事例の一つとして、
血栓の原因となりうる心房細動と呼ばれる症状を早期発見し、脳梗塞などの予防が期待されるそうです。
ウェアラブルデバイスの進化により、様々な病気の予防や早期発見に利用されています。
この記事では、ウェアラブルデバイスの代表格であるApple Watchのアプリを、HealthKitを絡めて作ってみたいと思います。
WatchAppとHealthKitの雰囲気をまとめてキャッチアップしていきましょう。
作ってみる
今回はできるだけ、iOS側のコードを書かずに、WatchOS側だけでHealthStoreの[水分摂取量]を操作するアプリを作ってみましょう。
なお、Xcode 10.1
を前提にしています。
Watch Simulatorを起動する
兎にも角にも、まずはWatch SimulatorをXcodeから起動してみます。
-
プロジェクトの作成する
- Project template では
iOS App with WatchKit App
を選択してください - Project optionsではNotificationもComplicationもTestもしないので、全てのチェックを外してOKです。
- Project template では
-
ビルドターゲットをWatch Appにする
-
シミュレータを指定する
-
実行する
すると、指定した iPhone と Watch のシミュレータが起動して、Watchの方には黒い画面が表示されます。
これで、WatchAppの開発ができるようになりました
HealthStoreDataにアクセスできるようにする
それでは次にHealthKitを利用して、HealthStoreDataにアクセスできるようにします。
まずはiOS側の設定です。
-
アプリの
Info.plist
に、なぜアプリがHealthDataを書込・読込したいかを記載する- 今回はサンプルなので適当に
hoge
とかでいいです - HealthDataのアクセス権限にはWriteとReadがあります
- Write権限は、書込権限と、このアプリの書込データの読込権限が付与されます
- Read権限は、全てのアプリの書込データを読み取る権限が付与されます
<key>NSHealthShareUsageDescription</key> <string>[読み込む理由をここに記載する]</string> <key>NSHealthUpdateUsageDescription</key> <string>[書き込む理由をここに記載する]</string>
- 今回はサンプルなので適当に
-
iOS側に適当にボタンを配置して、ボタンが押された時のコードを以下のように書く
import UIKit import HealthKit class ViewController: UIViewController { let store = HKHealthStore() @IBAction func tapped() { // 水分摂取量データにアクセスできるよう、リクエストする let sharedTypes: Set<HKSampleType> = [HKSampleType.quantityType(forIdentifier: .dietaryWater)!] store.requestAuthorization(toShare: sharedTypes, read: sharedTypes) { _, _ in } } }
-
実行ターゲットをiOS側にして、実行する
-
iOS側のSimulatorで設置したボタンをタップする
Health Accessの設定画面が表示されましたね。アクセスを全て許可にしたら、水分摂取量データの読取と書込ができるようになります。
ちなみに、Watch側で HKHealthStore の requestAuthorization
をコールすると、iPhone側で設定しろって表示されます。
水分摂取量データをWatchで表示する
-
InterfaceController.swift
に以下のコードを書くimport WatchKit import Foundation import HealthKit class InterfaceController: WKInterfaceController { let store = HKHealthStore() // 水摂取量を表すデータタイプ let waterType = HKSampleType.quantityType(forIdentifier: .dietaryWater)! // 今回は単位をミリリッターに固定 let unit = HKUnit.literUnit(with: .milli) // 水摂取量。更新されたら、Labelを更新する var waterIntake: Double = 0 { didSet { intakeLabel.setText("\(waterIntake) ml") } } @IBOutlet weak var intakeLabel: WKInterfaceLabel! // 画面が表示される前に実行される override func willActivate() { loadWaterIntake() super.willActivate() } // HealthStoreから今日の水摂取量データを読込み、waterIntake propertyを更新する func loadWaterIntake() { let calendar = Calendar(identifier: .gregorian) let today = calendar.dateComponents([.year, .month, .day], from: Date()) let start = calendar.date(from: today)! let predicate = HKQuery.predicateForSamples(withStart: start, end: start.addingTimeInterval(60*60*24)) let query = HKSampleQuery(sampleType: waterType, predicate: predicate, limit: HKObjectQueryNoLimit, sortDescriptors: nil) { _, samples, _ in let quantities: [HKQuantitySample]? = samples?.compactMap { $0 as? HKQuantitySample } self.waterIntake = quantities?.reduce(0) { $0 + $1.quantity.doubleValue(for: self.unit) } ?? 0 } store.execute(query) } }
-
Interface.storyboard
にLabelを追加する
これで、読取ることができるようになりました
起動してみると、おそらく0.0 ml
と表示されますので、iOSのシミュレータのHealth Appから水分の値を追加し、再度、Watch Appを起動してみてください。
すると、追加した値が表示されると思います。
(この辺の更新タイミングがまちまちで、追加後すぐにはwatch側で取得することができないことが多かったです。)
水分摂取量データをWatchから書き込む
最後に水分摂取量データをWatchから書き込んでみましょう。
Watchの入力インターフェースはかなり貧弱なので、ボタンをタップすると水摂取量を200mlの追加します。(コップ一杯が約200mlらしい)
この辺の値はiOSアプリ側でユーザが設定できるようにしたりすると便利かもしれません。
-
InterfaceController.swift
に以下のコードを追加する@IBAction func tapped() { addWaterIntake() } // HealthStoreに水分を200ml摂取したことを書き込み、waterIntakeの値を更新する func addWaterIntake() { let now = Date() let waterIntake = HKQuantitySample(type: waterType, quantity: HKQuantity(unit: unit, doubleValue: 200), start: now, end: now) store.save(waterIntake) { _, _ in self.loadWaterIntake() } }
-
Interface.storyboard
にButtonを追加する
これで、Watchから水摂取量データの追加ができるようになりました
Watch Appを起動し、ボタンを押すと、200ml追加されます。
終わりに
どうでしたでしょうか? 意外と簡単にできたかと思います。
エラー処理を全部すっ飛ばしてますが、本番コードではきちんと処理してくださいね。
本当はComplicationの表示までやりたかったんですが、ちょっと疲れたので今回はここまで。
HealthKitってどんなデータ扱えるの?って人は以下の記事も参照ください。