做者:ANUSHK MITTAL,時間:2016/6/18
翻譯:BigNerdCoding, 若有錯誤歡迎指出。原文連接html
當今關於睡眠革命的話題的討論很是熱烈,人們也比以往任什麼時候候都更加的好奇。他們關心的內容不只有在何時他們睡着了,還有那些經過分析過去一段時間以來自身睡眠數據所揭示出來的睡眠趨勢。隨着包括硬件等技術的進步,尤爲是智能手機的普及將這個看似正在不斷升溫的話題帶到了一個全新的境界。ios
蘋果公司提供了一種很是酷的方式來安全的與我的健康信息進行交互而且經過預裝的內置Health應用將這些健康信息存儲起來。經過HealthKit框架你不只能夠建立一個身體素質的應用,還能夠訪問到用戶的睡眠分析數據。git
在這篇教程中,我會對HealthKit框架作一個簡介,而且演示若是使用該框架建立一個睡眠分析的簡單應用。github
HealthKit框架提供了數據結構以便咱們可以將數據存儲到名爲HealthKit store的加密數據庫中。咱們能夠經過HKHealthStore類來對該加密數據庫進行訪問。iPhone和iWatch都有本身的HealthKit store,二者之間的健康數據會進行同步。然而,對iWatch中的老舊數據進行定時清理有助於節省iWatch的空間。HealthKit和Health應用並不存在於iPad中。算法
若是你想建立一個iOS或者watchOS上基於健康數據的應用話,HealthKit對你來講將是一個強大的工具。該框架被設計用來管理那些來源普遍的數據,而且基於用戶的偏心對這些來源不一樣的數據進行合併。應用也能夠訪問這些來源不一樣的元素數據,並自身對其進行合併處理操做。除了用於對身體的測量、體質和養分的分析,這些數據還能夠用來對用戶的睡眠進行分析。數據庫
在本文的剩餘部分,我將會爲你演示在iOS平臺上如何使用HealthKit框架來保存和訪問睡眠分析數據。這些方法一樣適用於watchOS平臺。請注意教程中的實例Xcode7上面使用Swift2.0實現的,因此在跟隨我腳步以前請確保你的Xcode是7以上的版本。安全
在咱們進行下一步以前,請先下載起始工程並將其解壓。我已經在工程裏面爲你建立好了帶有基本功能的用戶界面。當你運行工程的時候,你將會看見一個計時功能的UI界面(當你按下開始按鍵的時候會統計時間)。數據結構
咱們應用的目標是經過Start和Stop按鍵保持睡眠分析信息並取回該數據。爲了使用HealthKit,首先你必須讓你的應用得到受權。在你的app工程裏面選中當前目標,而後選擇capabilities並打開HealthKit功能。app
下一步你須要使用下面的代碼在ViewController類裏面建立HKHealthStore類實例:框架
let healthStore = HKHealthStore()
在後面你將會使用這個HKHealthStore實例來訪問HealthKit store。
正如前面提到的,HealthKit須要用戶受權才能夠控制他們的健康數據。因此在得到對用訪問(讀寫)用戶的健康數據以前,咱們首先須要請求用戶的受權贊成。爲了實現目的,咱們首先導入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") } } }
這段代碼將會提示用戶容許或者拒絕用戶的受權請求。在completion block裏面你能夠對成功或者錯誤進行處理而且獲得最終的結果。並非全部的用戶都會給予你相應的權限,你須要妥善的處理好用戶拒絕的狀況。
可是爲了測試的目的,你必須選擇容許應用得到訪問設備中健康數據的的權限。
首先,咱們如何檢索到睡眠分析數據呢?根據蘋果官方的文檔,每個睡眠分析樣本都有一個惟一值。爲了表示用戶在牀上和睡覺兩種狀態,HealthKit使用了兩個以上時間可能重疊的樣本。經過比較這些樣本的起始和終止時間,app能夠計算出下面這些相關的統計數據:
用戶入睡花費的時間
用戶在實際睡覺時間在牀上時間的佔比
用戶醒了依然在牀上的次數
用戶在牀上和睡眠花費的總時間
簡單來講,你能夠經過下面的方法來將睡眠數據保存到HealthKit store:
咱們定義兩個對應開始時間和結束時間的NSDate對象。
使用HKCategoryTypeIdentifierSleepAnalysis來建立一個HKObjectType實例
咱們須要建立一個HKCategorySample類型的對象。你一般會使用類別樣原本紀錄這些睡眠數據。使用單個樣原本表示用戶在牀上或者睡着了的時間段。因此咱們建立一個在牀上以及一個睡着了的樣本,兩種的時間段有重疊。
最後,咱們使用HKHealthStore中的saveObject方法來保存對象。
編輯提醒:針對樣本的類型,你能夠查看HealthKit Constants Reference來了解。
若是你將上面的方法轉化爲Swift語言,下面就是實現上面保存在牀上和睡着了兩個樣本數據的代碼片斷。請將這些方法插入到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 } }) } }
這個函數能夠在咱們須要將睡眠分析數據保存到HealthKit中的時候調用。
爲了讀取出睡眠分析數據,咱們須要創造一個隊列。首先你須要定義一個HKCategoryTypeIdentifierSleepAnalysis類別的HKObjectType對象。你可能會使用起始和結束數據做爲條件來篩選位於這段時間的數據。你還須要建立一個sortDescriptor來對查詢出來的數據進行排序。
檢索睡眠數據的代碼以下:
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) } }
上面的代碼會查出全部的睡眠數據並按照降序的方式進行排列。而後每個查詢結果都按照:起始時間、結束時間、類型值(例如:在牀上仍是睡着了)的形式打印出來。我在查詢中經過設置limit只取最後的30個樣本。你也能夠經過predicate方法選擇你自定義的起始和結束時間。
在演示應用中,我使用了NSTimer來紀錄點擊開始按鍵後流失的時間。當點擊開始和結束按鍵的時候都會建立一個NSDate對象,而且將通過的時間做爲睡眠分析數據進行保存。在點擊結束按鍵的時候能夠觸發調用saveSleepAnalysis()和retrieveSleepAnalysis()方法取保存和查詢睡眠數據。
@IBAction func stop(sender: AnyObject) { endTime = NSDate() saveSleepAnalysis() retrieveSleepAnalysis() timer.invalidate() }
在你本身的app中,你可能會改變NSDate對象並選擇與之相關的起始和結束時間來保存在牀上和睡覺的值。
若是你作出了修改的話,你能夠容許程序並點擊開始按鍵開始計時。讓程序運行幾分鐘而後點擊中止按鍵。而後你能夠打開Health應用,你就能夠看見睡眠數據了。
HealthKit是設計用來爲app開發人員提供一個更加方便分享和訪問用戶數據的公共平臺,而且避免了任何數據的重複和不一致的可能性。在蘋果應用審覈指導中詳細的代表了:那些使用了HealthKit而且要求獲取讀寫權限的應用若是沒有清晰的代表的話那麼頗有可能會審覈不過。
若是應用保存一些假的或者不正確的數據到Health應用中的話也有可能沒法審覈經過。這意味着,你不能想本文中那樣很天真的使用一些算法去計算不一樣的健康數據。你應該使用內置的傳感器去讀取和處理那些數據和參數,從而避免計算錯誤數據。
完整的Xcode工程能夠在這裏下載獲得。