Edited at

Swift と HealthKit で栄養情報をためていく

More than 3 years have passed since last update.

こんにちは、大阪のお好み焼屋です。お好み焼は最高ですが、Swiftも最高ですね。そんなわけで先日リリースした、お好み焼の栄養成分をヘルスケア(Health.app)へ送るApp、その名もレコノミーに絡めて、HealthKitをSwiftで利用する話です。


HealthKit

iOS8で新たに加わったHealthKit。いまいち盛り上がっている感じもありませんが、とりあえずデータをためておけば後でなにかいいことがあるかも・・・というわけで、iOS9で加えられたHKCorrelationTypeIdentifierFoodをつかって複数の栄養素をまとめて「メニュー単品」としてHealth.appへ送ることにします。ここではサンプルとしてうち自慢のイカ玉をつかいます。

サンプルコードと参考スクリーンショット

Simulator Screen Shot Dec 19, 2015, 23.38.18.png


主な登場Class

HealthKit

HKUnit
単位

HKQuantity

HKQuantityType
量のタイプ

HKQuantitySample
モノ

「モノ」というのがよくわからないですが、とりあえずの目標がこれだと思ってください。


HKUnit, HKQuantity

順番が前後しますが、まずはHKQunatityの初期化メソッドです

init(unit unit: HKUnit!, doubleValue value: Double)

Unitは単位で、Quantityは量のことですね。unit単位にdoubleValueの値を与えてやることで量になります。100.0という数(Double)に単位グラム(HKUnit)を与えてやることで、「100グラム」という量になるわけです。

unitの初期化はいろいろなやり方が用意されています

HKUnit.percentUnit()

HKUnit(fromString: "cm")
HKUnit.gramUnitWithMetricPrefix(.Kilo)

ひとつめはいわゆるConvenience Constructor的なやつで、ここでは「%」ですが、他にも結構な数が用意されています。

2つめは単位を文字列で表す方法(ここではセンチメートル)。”m/s^2”(加速度|$m/s^2$)なんかも可能。

3つめは読んだ通り「メートル法のグラム単位をキロで」。これでキログラムになります。

let kcalUnit = HKUnit.kilocalorieUnit()

let quantity = HKQuantity(unit: kcalUnit, doubleValue: 347)


HKQuantityType, HKQuantitySample

次に量のタイプです。カロリーと一口にいっても、摂取したカロリーなのか(HKQuantityTypeIdentifierDietaryEnergyConsumed)、運動で消費したカロリーなのか(HKQuantityTypeIdentifierActiveEnergyBurned)、はたまた基礎エネルギーの消費なのか(HKQuantityTypeIdentifierBasalEnergyBurned)を、HKQuantityTypeでしっかり指定してやります。

これでようやく必要な要素がそろってHKQuantitySampleのインスタンス化ができるようになりました。

let type = HKQuantityType.quantityTypeForIdentifier(HKQuantityTypeIdentifierDietaryEnergyConsumed)!

let date = NSDate()
let ikatamaEnergySample = HKQuantitySample(type: type, quantity: quantity, startDate: date, endDate: date)

これでイカ玉のカロリーが完成です。あとは同じ手順で他の必要な栄養素を単位に気をつけつつインスタンス化していきます。

たとえばプロテイン(蛋白質)はこんな具合

let gramUnit = HKUnit.gramUnit()

let proteinQuantity = HKQuantity(unit: gramUnit, doubleValue: 18.9)
let proteinType = HKQuantityType.quantityTypeForIdentifier(HKQuantityTypeIdentifierDietaryProtein)!
let ikatamaProteinSample = HKQuantitySample(type: proteinType, quantity: proteinQuantity, startDate: date, endDate: date)


HKCorrelation

コードを見ていただければ一目瞭然だとおもいます。

var itemSet = Set<HKQuantitySample>() 

itemSet.insert(ikatamaEnergySample)
//// 必要な栄養のサンプルを`insert(_)`していく
let foodType = HKCorrelationType.correlationTypeForIdentifier(HKCorrelationTypeIdentifierFood)!
let ikatama = HKCorrelation(type: foodType, startDate: date, endDate: date, objects: itemSet, metadata: metadata)


HKHealthStore

あとはストアのアベイラビリティをチェックして、ストアへのアクセスをリクエストしてやります。フレームワークが面倒をみてくれます。

guard HKHealthStore.isHealthDataAvailable() else { return }

let healthStore = HKHealthStore()

let typeSet: Set<HKSampleType> = [energyType, proteinType]
healthStore.requestAuthorizationToShareTypes(typeSet, readTypes: nil) { success, error -> Void in
// if request is approved
healthStore.saveObject(ikatama) { success, error in
if success { print("DONE!!") }
}
}

無事送れています。

Simulator Screen Shot Dec 20, 2015, 17.40.31.png


最後に

あわてて書いたのであまりSwiftっぽい話はできませんでしたが、レコノミー内ではenumを使いまくったりして、とても楽しく書くことができています。また機会があればenum+protocolの話も書ければと思っています。ありがとうございました。