如今,睡眠革命逐漸成為一種時尚,跟之前相比,人們不僅想知道自己的睡眠時間,同時對用于分析他們一定時間段內(nèi)睡眠狀態(tài)的數(shù)據(jù)感興趣。包括硬件技術(shù)在內(nèi)的,尤其是手機(jī)技能的提升,為用戶這一日益增長的需求帶來了全新的希望.

蘋果提供了一種安全、炫酷的方式來顯示用戶的個人健康信息,并將這些信息安全的存儲在 Health 這個內(nèi)置的應(yīng)用中。你不僅可以使用 HealthKit 來 創(chuàng)建一個健身應(yīng)用 ,該框架還允許你訪問睡眠的詳細(xì)數(shù)據(jù)。這本次教程中,我將會給大家簡要的介紹 HealthKit 這個框架,并演示如何創(chuàng)建一個簡單的睡眠分析的應(yīng)用。
**簡介 **
HealthKit 提供了一個名為 HealthKit store 的結(jié)構(gòu)用來存儲加密的數(shù)據(jù)。你可以使用HKHealthStore這個類來訪問這個數(shù)據(jù)庫。iPhone 和 Apple Watch 都有自己的 HealthKit store,他們之間的健康數(shù)據(jù)是同步。需要注意的是,在 Apple Watch 上老的數(shù)據(jù)會被定期的清除以節(jié)省空間。并且 ,iPad不支持HealthKit 和 Health 。
如果你想基于健康數(shù)據(jù)創(chuàng)建一個 iOS 或者 watchOS 應(yīng)用,HealthKit 是一個非常強(qiáng)大的工具。它被設(shè)計的目的就是管理廣泛地數(shù)據(jù)源,并且根據(jù)用戶的偏好自動地合并不同來源的數(shù)據(jù)。應(yīng)用程序還可以訪問每一條原始數(shù)據(jù),并且合并他們。這些數(shù)據(jù)不僅能夠用于身體評估,健康狀況評估以及營養(yǎng)狀況評估,還能夠用于分析睡眠質(zhì)量。
接下來,我將會向你展示在 iOS 上如何利用 HealthKit 保存和訪問睡眠數(shù)據(jù)。這種方法也同樣適合 watchOS 上的應(yīng)用。請注意本次教程使用的是 Swift 2.0 和 Xcode 7。因此,請確保你跟隨此教程的時候使用的是 Xcode 7(或者以上)。
在此之前,下載最開始的工程 并解壓。我已經(jīng)為你創(chuàng)建了基本功能的用戶界面。當(dāng)你運(yùn)行這個工程的時候,你將會看到一個定時器的 UI ,當(dāng)你按下開始按鈕以后就會顯示計時。
** 使用 HealthKit**
我們使用這個應(yīng)用的目的是使用開始和停止按鈕來保存睡眠分析信息和復(fù)取數(shù)據(jù)。要使用 HealthKit,你必須給你的應(yīng)用授權(quán)。也就是在你的應(yīng)用中,按著 target -> capabilities -> 打開HealthKit開關(guān) 這個步驟

接下來,你需要用下面的代碼在 ViewController 類中創(chuàng)建一個 HKHealthStore 的實(shí)例:
let healthStore = HKHealthStore()
隨后我們將使用 HKHealthStore 這個實(shí)例來訪問 HealthKit store。
如之前所說, HealthKit 授予用戶權(quán)限來訪問他們的健康數(shù)據(jù)。所以你在獲得用戶的睡眠分析數(shù)據(jù)權(quán)限(讀/寫)之前,你必須現(xiàn)請求用戶的許可。要做到這一點(diǎn),首先要導(dǎo)入內(nèi)置的 HealthKit 框架,然后更新 viewDidLoad 里面的方法,如下:
override func viewDidLoad() {
super.viewDidLoad()
let typestoRead = Set([
HKObjectType.categoryTypeForIdentifier(HKCategoryTypeIdentifierSleepAnalysis)!
])
let typestoShare = Set([
HKObjectType.categoryTypeForIdentifier(HKCategoryTypeIdentifierSleepAnalysis)!
])
self.healthStore.requestAuthorizationToShareTypes(typestoShare, readTypes: typestoRead) { (success, error) -> Void in
if success == false {
NSLog(" Display not allowed")
}
}
}
這段代碼將提示用戶允許或拒絕請求的訪問的權(quán)限。在閉包中,你可以對成功或者失敗進(jìn)行處理,并得到最終結(jié)果。用戶沒有必要授予你的應(yīng)用所有你請求的權(quán)限。所以在你的應(yīng)用中你必須妥善的處理這些錯誤。
但是出于測試的目的,你必須選擇“允許”選項(xiàng)來授權(quán)你的應(yīng)用能訪問你設(shè)備上的健康數(shù)據(jù)。

寫入睡眠分析數(shù)據(jù)
首先,我們?nèi)绾螐?fù)取睡眠分析數(shù)據(jù)呢?根據(jù)蘋果文檔,每個睡眠分析樣品只能有一個值。為了區(qū)分用戶是在床上還是睡著了,HealthKit 用了兩個或者兩個以上的重疊時間的樣本。通過比較這些樣品的開始和結(jié)束時間,應(yīng)用就可以計算出一些次要的統(tǒng)計數(shù)據(jù):
用戶進(jìn)入睡眠所花費(fèi)的時間
用戶在床上的時間和實(shí)際睡眠時間的百分比
用戶在床上醒來的次數(shù)
用戶在床上和睡著的時間的總和

簡單地說,你按照下面的方法來保存你的睡眠分析數(shù)據(jù)到 HealthKit 商店:
1、我們需要定義兩個
NSDate的對象用于開始時間和結(jié)束時間。2、用
HKCategoryTypeIdentifierSleepAnalysis創(chuàng)建一個HKObjectType的實(shí)例。3、我們需要創(chuàng)建一個新的
HKCategorySample類型的對象,你通常使用一類的樣本來記錄睡眠時間,單個的樣本代表用戶在床上或者在睡覺的時間段。因此,我們將會創(chuàng)建一個在床上和一個睡著了的重疊時間樣本。4、最后,我們用
HKHealthStore的saveObject方法來保存上述實(shí)例。
如果你想用 Swift 實(shí)現(xiàn)上述所有,這里有保存在床上和睡眠中睡眠分析數(shù)據(jù)的代碼片段。請把這些代碼插入在ViewController類中:
func saveSleepAnalysis() {
// alarmTime and endTime are NSDate objects
if let sleepType = HKObjectType.categoryTypeForIdentifier(HKCategoryTypeIdentifierSleepAnalysis) {
// we create our new object we want to push in Health app
let object = HKCategorySample(type:sleepType, value: HKCategoryValueSleepAnalysis.InBed.rawValue, startDate: self.alarmTime, endDate: self.endTime)
// at the end, we save it
healthStore.saveObject(object, withCompletion: { (success, error) -> Void in
if error != nil {
// something happened
return
}
if success {
print("My new data was saved in HealthKit")
} else {
// something happened again
}
})
let object2 = HKCategorySample(type:sleepType, value: HKCategoryValueSleepAnalysis.Asleep.rawValue, startDate: self.alarmTime, endDate: self.endTime)
healthStore.saveObject(object2, withCompletion: { (success, error) -> Void in
if error != nil {
// something happened
return
}
if success {
print("My new data (2) was saved in HealthKit")
} else {
// something happened again
}
})
}
}
當(dāng)我們想把睡眠分析數(shù)據(jù)保存到 HealthKit 的時候上述方法將會被調(diào)用。
** 讀取睡眠分析數(shù)據(jù)**
要讀取睡眠分析數(shù)據(jù),我們需要創(chuàng)建一個query。首先你需要用 HKCategoryTypeIdentifierSleepAnalysis 定義一個 HKObjectType類型的實(shí)例,你可能還需要一個謂詞來篩選你用開始時間和結(jié)束時間復(fù)取的數(shù)據(jù),也就是你想要檢索的時間范圍內(nèi)的 NSDate 類型的對象。你還需要創(chuàng)建一個 sortDescriptor 排序的檢索詞來篩選出你想要的結(jié)果。
你的檢索睡眠分析數(shù)據(jù)的代碼應(yīng)改像下面這樣:
func retrieveSleepAnalysis() {
// first, we define the object type we want
if let sleepType = HKObjectType.categoryTypeForIdentifier(HKCategoryTypeIdentifierSleepAnalysis) {
// Use a sortDescriptor to get the recent data first
let sortDescriptor = NSSortDescriptor(key: HKSampleSortIdentifierEndDate, ascending: false)
// we create our query with a block completion to execute
let query = HKSampleQuery(sampleType: sleepType, predicate: nil, limit: 30, sortDescriptors: [sortDescriptor]) { (query, tmpResult, error) -> Void in
if error != nil {
// something happened
return
}
if let result = tmpResult {
// do something with my data
for item in result {
if let sample = item as? HKCategorySample {
let value = (sample.value == HKCategoryValueSleepAnalysis.InBed.rawValue) ? "InBed" : "Asleep"
print("Healthkit sleep: \(sample.startDate) \(sample.endDate) - value: \(value)")
}
}
}
}
// finally, we execute our query
healthStore.executeQuery(query)
}
}
這段代碼查詢了在 HealthKit 上的所有睡眠分析數(shù)據(jù)并按降序排列。然后每天結(jié)果上都帶著是在床上的開始結(jié)束時間或者在睡覺的開始結(jié)束時間被打印出來。我已經(jīng)設(shè)置了上限30用來檢索最后記錄的30個樣本。你也可以用謂詞的方法來選擇你的自定義開始時間和結(jié)束時間。
應(yīng)用測試
對于這個 demo,我已經(jīng)使用 NSTimer 來顯示你按下按鈕之后經(jīng)過的時間。當(dāng)開始和結(jié)束按鈕按下的時候?qū)?chuàng)建 NSDate 的對象來保存所經(jīng)過的時間作為睡眠分析數(shù)據(jù)。在停止的方法中,你可以調(diào)用 saveSleepAnalysis() 和 retrieveSleepAnalysis方法來保存和獲得睡眠數(shù)據(jù)。
@IBAction func stop(sender: AnyObject) {
endTime = NSDate()
saveSleepAnalysis()
retrieveSleepAnalysis()
timer.invalidate()
}
在你的應(yīng)用程序中,你也許想要改變 NSDate 對象來選擇相關(guān)的開始和結(jié)束時間(可能不同)來保存在床上和睡眠的的值。
一旦你做了這些改變,你可以運(yùn)行這個 demo 然后開始計時。讓它運(yùn)行幾分鐘,然后點(diǎn)擊停止按鈕。然后,打開 Health 這個應(yīng)用,你就可以找到你的睡眠數(shù)據(jù)。

一些關(guān)于 HealthKit 應(yīng)用的建議
HealthKit 旨在提供一個公共平臺,使應(yīng)用程序開發(fā)人員能夠很容易地共享和訪問用戶的數(shù)據(jù),并避免任何可能的重復(fù)或不一致的數(shù)據(jù)。蘋果審核指南對使用 HealthKit 有很明確的要求,如果對用戶的讀/寫權(quán)限請求沒有明確的描述就很可能導(dǎo)致應(yīng)用程序被拒絕。
應(yīng)用如果保存?zhèn)卧旎蛘咤e誤的數(shù)據(jù)到健康應(yīng)用的話也將被拒絕。這就意味著,你不能像在本次教程中睡眠分析這樣天真的以你的算法計算不同的健康值。你應(yīng)該嘗試使用內(nèi)置的傳感器數(shù)據(jù)讀取和操作一些參數(shù),以避免計算錯誤。
關(guān)于完整的 Xcode 項(xiàng)目,你可以在 這里 看到。