今天碍侦,睡眠革命已經(jīng)成為一種時尚惯退,并且人們比以往任何時候都想了解他們睡眠的時間,更想分析收集自己睡眠時間趨勢透露出來的信息咒锻,先進的技術(shù)冷冗,硬件,手機把這個看似不斷增長的項目帶入了一個新的時代惑艇。
蘋果提供了一種很酷并且安全的方式來與用戶個人健康信息進行通信蒿辙,并且通過內(nèi)置的健康A(chǔ)pp對這些信息進行安全的存儲。你不僅可以使用HealthKit建立一個健身的應(yīng)用程序滨巴,同時這個框架也允許你訪問睡眠質(zhì)量等數(shù)據(jù)思灌。
在本教程中,我會快速的向你介紹這個HealthKit框架恭取,并且掩飾如何創(chuàng)建一個基于睡眠數(shù)據(jù)分析的簡單應(yīng)用泰偿。
Introduction---前言介紹
HealthKit框架提供了一個結(jié)構(gòu)用于將數(shù)據(jù)以加密的數(shù)據(jù)庫的方式保存在 HealthKit store
中,你可以使用HKHealthStore類訪問此數(shù)據(jù)庫蜈垮, iPhone
和Apple Watch
都有他們自己的HealthKit store
耗跛,健康數(shù)據(jù)可以在iPhone
和Apple Watch
之間同步裕照。然而為了節(jié)省空間,Apple Watch
上過早的數(shù)據(jù)會被周期性的清除调塌。HealthKit框架和Health 應(yīng)用并不能在iPad上使用晋南。
如果你想創(chuàng)建一個基于健康數(shù)據(jù)的iOS或者watchOS應(yīng)用,HealthKit將是一個強大的工具羔砾。它的設(shè)計目的就是在更廣泛的資源上來管理數(shù)據(jù)负间,自動的合并基于用戶偏好的不同來源的數(shù)據(jù)。應(yīng)用程序可以訪問各個資源的原始數(shù)據(jù)并且可以合并數(shù)據(jù)本身姜凄,不僅可以針對身體的測量政溃,健身或營養(yǎng)情況,該數(shù)據(jù)也可以用于睡眠質(zhì)量等分析态秧。
在接下來的文章中玩祟,我將告訴你如何使用HealthKit framework在iOS上保存和訪問睡眠分析數(shù)據(jù),當(dāng)然屿聋,方法同樣適用于watchOS的應(yīng)用空扎。值得注意的是,本教程使用Swift 2.0 和 Xcode 7.編寫润讥,所以確保你的Xcode版本在7.0以上转锈。
在開始之前,請下載啟動項目并解壓縮楚殿,我已經(jīng)創(chuàng)建了一個基本功能的用戶界面撮慨,當(dāng)你運行啟動這個項目,你會看到一個計時器脆粥,顯示你按下按鈕之后經(jīng)過的時間砌溺。
Working with the HealthKit Framework---HealthKit框架的使用
我們應(yīng)用程序的目的是利用Start
和 Stop
按鈕來實現(xiàn)保存睡眠分析信息和取出數(shù)據(jù),要使用HealthKit必須在一開始的時候授權(quán)你的應(yīng)用程序訪問HealthKit:打開你的Xcode->project->target ,打開HealthKit功能变隔。如下圖
接下來规伐,需要創(chuàng)建一個HKHealthStore的實例,在你的ViewControlle類中粘貼如下代碼:
let healthStore = HKHealthStore()```
稍后匣缘,我們會使用HKHealthStore實例來訪問`HealthKit store`
正如之前提到的猖闪,HealthKit必須經(jīng)過授權(quán)才可以訪問并控制他們的健康數(shù)據(jù),所以你必須先請求用戶的許可才可以訪問(讀/寫)用戶的睡眠分析數(shù)據(jù)肌厨。要做到這一點培慌,第一步首先到導(dǎo)入內(nèi)置的HealthKit框架( HealthKit framework)并且更新你的`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)限請求柑爸,在完成的block中可以對成功或失敗出錯進行處理吵护,并且也可以得到最終的結(jié)果。當(dāng)然用戶并不是必須或者一定會同意你的應(yīng)用程序所有的權(quán)限請求,所以你必須在程序中妥善的處理錯誤情況馅而。
但是出于測試目的祥诽,你必須選擇“允許”選項,授予應(yīng)用程序權(quán)限訪問設(shè)備上的健康數(shù)據(jù)用爪。如下圖:
Writing Sleep Analysis Data---寫入睡眠分析數(shù)據(jù)
首先原押,我們?nèi)绾尾拍塬@取睡眠分析數(shù)據(jù)呢胁镐?根據(jù)蘋果的官方文檔偎血,每個睡眠分析樣本只能有一個值,這個值代表用戶無論躺在床上還是已經(jīng)睡著了盯漂,HealthKit用兩個或者多個重復(fù)時間的樣本颇玷,通過比較這些樣本的開始和結(jié)束時間,應(yīng)用程序統(tǒng)計計算出來的一個值:
the amount of time it takes for the user to fall asleep
the percentage of time in bed that the user actually sleeps
the number of times the user wakes up while still in bed
the total amount of time spent both in bed and asleep
簡單來說就缆,按照下面的方法把分析得到的睡眠數(shù)據(jù)保存到HealthKit store
:
1.我們需要定義對應(yīng)于開始時間和結(jié)束時間的兩個`NSDate`對象帖渠。
2.然后我們使用`HKCategoryTypeIdentifierSleepAnalysis`創(chuàng)建一個`HKObjectType`實例。
3.我們需要創(chuàng)建一個`HKCategorySample`類型的新對象竭宰,通常使用樣本的類別來記錄睡眠數(shù)據(jù)空郊。每個 樣本代表用戶躺在床上或者進入睡眠的時間段。所以我們會同時創(chuàng)建一個躺在床上的樣本和一個進入睡眠狀態(tài)的樣本切揭。
4.最后我們用`HKHealthStore`的`saveObject`方法來保存對象狞甚。
注意的是:對于樣本的類型,可以查看HealthKit Constants Reference
鏈接中的內(nèi)容是Objective-C版本廓旬,如果你要翻譯成swift版本哼审,這里是保存睡眠數(shù)據(jù)的代碼,請?zhí)砑拥?code>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
}
})
}
}```
上述方法在我們想要把睡眠分析數(shù)據(jù)保存到`HealthKit`的時候調(diào)用孕豹。
###Reading Sleep Analysis Data---讀取睡眠分析數(shù)據(jù)
要想獲取睡眠分析數(shù)據(jù)涩盾,需要創(chuàng)建一個`query`(查詢語句),首先定義一個`HKObjectType`類別`HKCategoryTypeIdentifierSleepAnalysis`,然后你還需要是用一個時間條件使用`startDate`和`endDate`(NSDate類型)來獲取檢索時間范圍內(nèi)的數(shù)據(jù)励背,你還需要創(chuàng)建一個`sortDescriptor`排序的檢索查詢以獲取所期望的數(shù)據(jù)春霍。
下面是檢索睡眠分析數(shù)據(jù)的示例代碼:
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ù),然后降序排列叶眉,每個查詢語句都打印了`startDate`,`endDate`,`value`,上述代碼已經(jīng)設(shè)置了上限30天來檢索過去30天的樣本终畅,你也可以自定義方法來選擇你自己認為的開始和結(jié)束時間。
###App Testing---測試
對于上面的Demo竟闪,我使用NSTimer來顯示距離按下按鈕的時間离福,保存這個按鈕的開始和結(jié)束時間內(nèi)(NSDate對象)的睡眠分析數(shù)據(jù),在停止的方法里炼蛤,可以調(diào)用`saveSleepAnalysis()`和`retrieveSleepAnalysis()`方法來保存和獲取睡眠數(shù)據(jù)妖爷。
@IBAction func stop(sender: AnyObject) {
endTime = NSDate()
saveSleepAnalysis()
retrieveSleepAnalysis()
timer.invalidate()
}
在你的app里,你需要改變NSDate對象來選擇相應(yīng)的開始和結(jié)束時間(可能不相同)來保存躺在床上和進入睡眠狀態(tài)的值。
一旦更改了之后絮识,你就可以運行你的程序啟動定時器绿聘,,讓它運行幾分鐘之后按下停止按鈕次舌,打開Health app熄攘,你就會看到相應(yīng)的睡眠數(shù)據(jù)。如下圖:
![](http://upload-images.jianshu.io/upload_images/701353-6f7993c57e45bca8.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
###Some Advices for HealthKit Apps---總結(jié)與建議
HealthKit蘋果設(shè)計這個框架的目的就是提供給開發(fā)者一個共享平臺彼念,用以分享或訪問用戶的數(shù)據(jù)挪圾,避免數(shù)據(jù)中可能的重復(fù)和不一致。蘋果的審核說明明確指出逐沙,使用了HealthKit并要求讀寫權(quán)限的但是對于數(shù)據(jù)使用沒有明確的示例和說明的話會被拒哲思。
保存假的或者不正確的數(shù)據(jù)到Health App也會被拒(悲劇)吩案,意味著對于計算不同的健康值你的算法不能太low棚赔,或者存在僥幸心理。就像本教程中睡眠分析計算那樣徘郭,你應(yīng)該嘗試使用內(nèi)置的傳感器數(shù)據(jù)讀取和處理任何參數(shù)靠益,以避免錯誤的計算數(shù)據(jù)。
有關(guān)完整的Xcode項目残揉,[看這里](https://github.com/appcoda/SleepAnalysis).