在HeatherKit使用Swift做睡眠分析

今天愕把,睡眠的變革是一種時(shí)尚拣凹,用戶比以往任何時(shí)候都好奇要了解他們已經(jīng)睡了多久森爽,更要通過收集一些數(shù)據(jù)來分析他們的睡眠趨勢(shì)。現(xiàn)在科技的進(jìn)步特別在硬件和手機(jī)已經(jīng)帶入我們進(jìn)入了一個(gè)全新的時(shí)代嚣镜。

蘋果提供了一個(gè)很酷的以安全的方式與用戶的個(gè)人健康信息溝通爬迟,并通過內(nèi)置的應(yīng)用程序健康安全存儲(chǔ)的信息。您不僅可以使用HealthKit建立一個(gè)健身的應(yīng)用程序菊匿,該框架還允許您訪問睡眠分析數(shù)據(jù)付呕。

在本教程中,我會(huì)給你一個(gè)快速介紹HealthKit框架跌捆,并演示如何構(gòu)建睡眠分析簡(jiǎn)單的應(yīng)用程序徽职。

介紹

HealthKit提供了一種被稱為HealthKit存儲(chǔ)加密的數(shù)據(jù)庫結(jié)構(gòu)去存儲(chǔ)數(shù)據(jù)。你能使用HKHealthStore類去訪問這個(gè)數(shù)據(jù)庫佩厚。無論在iPhone上還是Apple Watch上都有他們自己的HealthKit數(shù)據(jù)存儲(chǔ)姆钉。健康數(shù)據(jù)在iPhone上和Apple Watch是同步的。然而為了節(jié)省空間Apple Watch上的數(shù)據(jù)會(huì)被周期性的清除抄瓦。HealthKit和健康A(chǔ)PP現(xiàn)在還不可以在iPad上使用潮瓶。

如果你想根據(jù)健康數(shù)據(jù)創(chuàng)建一個(gè)iOS或者watchOS應(yīng)用,HealthKit是一個(gè)強(qiáng)大的工具钙姊。它設(shè)計(jì)的目的是為了管理廣泛的數(shù)據(jù)來源毯辅,依據(jù)用戶的偏好設(shè)置自動(dòng)合并不同的數(shù)據(jù)來源。應(yīng)用程序能夠訪問每一個(gè)原始的數(shù)據(jù)并合并他們煞额。不僅對(duì)身體的測(cè)量悉罕,健身或營養(yǎng),該數(shù)據(jù)也可以用于睡眠分析立镶。

對(duì)于本文的其余部分壁袄,我將告訴你如何在iOS的上去利用HealthKit框架去訪問睡眠分析數(shù)據(jù)。相同的方法也可以使用在watchOS上媚媒。請(qǐng)注意本教程使用Swift2.0和XCode7.請(qǐng)確保使用XCode7或者更高的版本嗜逻。

在繼續(xù)之前,下載啟動(dòng)項(xiàng)目解壓缭召。我已經(jīng)為你寫好了基本的用戶界面栈顷。當(dāng)您運(yùn)行啟動(dòng)項(xiàng)目,你會(huì)看到一個(gè)計(jì)時(shí)器UI嵌巷,你按下啟動(dòng)按鈕后萄凤,標(biāo)簽上回顯示經(jīng)過的時(shí)間。

使用HealthKit框架工作

我們使用這個(gè)應(yīng)用程序的目的是使用開始和暫停按鈕保存睡眠數(shù)據(jù)和讀取數(shù)據(jù)搪哪。使用HealthKit你必須在應(yīng)用開始時(shí)候給HealthKit授權(quán)靡努。在你的應(yīng)用程序中,導(dǎo)航到你的當(dāng)前Target ->功能并打開HealthKit。


接下來惑朦,使用下面的代碼創(chuàng)建一個(gè)HKHealthStore實(shí)例在ViewController類中

let healthStore = HKHealthStore()

稍后我們將使用HKHealthStore實(shí)例訪問HealthKit存儲(chǔ)兽泄。

正如前面提到的,HealthKit授予用戶對(duì)他們的健康數(shù)據(jù)進(jìn)行控制漾月。所以病梢,你必須先請(qǐng)求用戶的許可才可以訪問(讀/寫)到用戶的睡眠分析數(shù)據(jù)。要做到這一點(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")
        }
    }
}

此代碼將提示用戶允許或拒絕請(qǐng)求的權(quán)限蜓陌。當(dāng)回調(diào)完成是你可以處理成功或者失敗,并獲得最終結(jié)果吩蔑。用戶沒有必要授權(quán)你的應(yīng)用所有的授權(quán)护奈。但是你必須在你的應(yīng)用中妥善處理錯(cuò)誤。

但是出于測(cè)試目的哥纫,你必須選擇“允許”選項(xiàng)霉旗,授予應(yīng)用程序權(quán)限訪問設(shè)備上的健康數(shù)據(jù)。

寫睡眠分析數(shù)據(jù)

首先蛀骇,我們?nèi)绾文茏x取睡眠分析數(shù)據(jù)厌秒?根據(jù)蘋果的文檔,每個(gè)睡眠分析樣品僅僅有一個(gè)值擅憔。代表用戶在床上睡了鸵闪,HealthKit能夠在重復(fù)的時(shí)間段中使用超過兩個(gè)或者更多的數(shù)據(jù)。通過比較這些樣品的開始和結(jié)束時(shí)間暑诸,應(yīng)用可以計(jì)算一些次要統(tǒng)計(jì):

  • 用戶入睡花費(fèi)的時(shí)間
  • 在床上和實(shí)際入睡的百分比
  • 用戶在睡覺中醒了多少次
  • 總共在床上花費(fèi)多長時(shí)間

簡(jiǎn)單地說蚌讼,你按照下面的方法來分析的睡眠數(shù)據(jù)并保存到HealthKit存儲(chǔ)中:

  • 我們需要定義兩個(gè)NSDate對(duì)象來比較開始時(shí)間和介紹時(shí)間
  • 我們使用HKCategoryTypeIdentifierSleepAnalysis創(chuàng)建一個(gè)HKObjectType實(shí)例
  • 我們需要?jiǎng)?chuàng)建一個(gè)HKCategorySample類型的實(shí)例。您通常使用類別的樣本來記錄睡眠數(shù)據(jù)个榕。個(gè)體樣品代表的時(shí)間段篡石,當(dāng)用戶是在床或睡著了。所以我們將創(chuàng)建一個(gè)在重復(fù)時(shí)間段內(nèi)在床上的樣本和睡著的樣本西采。
  • 最后我們將會(huì)保存這個(gè)對(duì)象使用HKHealthStore的saveObject方法
編者注:對(duì)于樣品類型凰萨,你需要查看一下[HealthKit Constants Reference](https://developer.apple.com/library/ios/documentation/HealthKit/Reference/HealthKit_Constants/index.html#//apple_ref/doc/uid/TP40014710).

如果你用Swift翻譯上面的代碼,下面是代碼片段保存用戶在床上和睡著的睡眠數(shù)據(jù)械馆。請(qǐng)把下面代碼放到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
            }
            
        })
        
    }
    
}

這個(gè)函數(shù)可以在我們需要保存用戶睡眠數(shù)據(jù)的時(shí)候調(diào)用胖眷。

讀取睡眠數(shù)據(jù)

為了讀取用戶數(shù)據(jù),我們需要新建一個(gè)查詢霹崎。你應(yīng)該首先為HKCategoryTypeIdentifierSleepAnalysis定義一個(gè)HKObjectType類別珊搀。你可能還需要一個(gè)謂詞去過濾這些重復(fù)數(shù)據(jù),你可能還需要一個(gè)謂詞來篩選使用開始日期和結(jié)束日期對(duì)應(yīng)的NSDate對(duì)象來檢索時(shí)間范圍內(nèi)的數(shù)據(jù)尾菇。您還需要建立一種描述排序的檢索查詢境析,選擇想要的結(jié)果囚枪。

你的睡眠分析代碼應(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)
    }
}

這些代碼查詢HeatherKit所有的睡眠數(shù)據(jù)然后以降序排列。每個(gè)查詢都打印出來了開始日期和結(jié)束日期的值類型簿晓。在床上或者睡覺。我已經(jīng)設(shè)置了30的上限千埃,至少讀取30組樣品數(shù)據(jù)憔儿。你也可以使用謂詞函數(shù)去自定義選擇你自己的開始日期和結(jié)束日期。

測(cè)試應(yīng)用程序

對(duì)于這個(gè)演示程序放可,在你點(diǎn)擊開始按鈕之后我們使用NSTimer來展示已經(jīng)過去的時(shí)間谒臼。NSDate對(duì)象被創(chuàng)建在你點(diǎn)擊了開始按鈕之后,睡眠數(shù)據(jù)被保存在你點(diǎn)擊了結(jié)束按鈕之后耀里。在暫停的方法中你可以調(diào)用saveSleepAnalysis()和retrieveSleepAnalysis()方法去保存和獲取睡眠數(shù)據(jù)蜈缤。

@IBAction func stop(sender: AnyObject) {
    endTime = NSDate()
    saveSleepAnalysis()
    retrieveSleepAnalysis()
    timer.invalidate()
}

在您的應(yīng)用程序,你可能要改變的NSDate對(duì)象來選擇相關(guān)的開始和結(jié)束時(shí)間(可能不同)冯挎,保存在床上和睡著的值底哥。

如果你做了更改,您可以運(yùn)行演示應(yīng)用程序房官,并開始計(jì)時(shí)趾徽。讓它開始運(yùn)行幾分鐘然后點(diǎn)擊暫停按鈕。然后打開健康A(chǔ)PP翰守,你就會(huì)看到睡眠數(shù)據(jù):

健康

HealthKit應(yīng)用的建議

HealthKit能夠很輕松地為開發(fā)人員提供一個(gè)共享的平臺(tái)和訪問用戶的數(shù)據(jù)孵奶,避免數(shù)據(jù)中的任何可能的重復(fù)或不一致。蘋果的審核指導(dǎo)使用HealthKit并要求讀/寫權(quán)限蜡峰,非常具體的表明可能導(dǎo)致被拒絕的應(yīng)用程序了袁。

在健康應(yīng)用程序中保存假的或者不正確的數(shù)據(jù)也可能會(huì)被拒絕。這意味著你不能像本教程這樣把你的健康分析算法寫的這么簡(jiǎn)單湿颅。你應(yīng)該嘗試使用內(nèi)置的傳感器數(shù)據(jù)讀取和處理任何參數(shù)载绿,以避免錯(cuò)誤的計(jì)算數(shù)據(jù)。

完整的項(xiàng)目你可以從這里下載.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末油航,一起剝皮案震驚了整個(gè)濱河市卢鹦,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌劝堪,老刑警劉巖冀自,帶你破解...
    沈念sama閱讀 221,695評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異秒啦,居然都是意外死亡熬粗,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,569評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門余境,熙熙樓的掌柜王于貴愁眉苦臉地迎上來驻呐,“玉大人灌诅,你說我怎么就攤上這事『” “怎么了猜拾?”我有些...
    開封第一講書人閱讀 168,130評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長佣盒。 經(jīng)常有香客問我挎袜,道長,這世上最難降的妖魔是什么肥惭? 我笑而不...
    開封第一講書人閱讀 59,648評(píng)論 1 297
  • 正文 為了忘掉前任盯仪,我火速辦了婚禮,結(jié)果婚禮上蜜葱,老公的妹妹穿的比我還像新娘全景。我一直安慰自己,他們只是感情好牵囤,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,655評(píng)論 6 397
  • 文/花漫 我一把揭開白布爸黄。 她就那樣靜靜地躺著,像睡著了一般揭鳞。 火紅的嫁衣襯著肌膚如雪馆纳。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,268評(píng)論 1 309
  • 那天汹桦,我揣著相機(jī)與錄音鲁驶,去河邊找鬼。 笑死舞骆,一個(gè)胖子當(dāng)著我的面吹牛钥弯,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播督禽,決...
    沈念sama閱讀 40,835評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼脆霎,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了狈惫?” 一聲冷哼從身側(cè)響起睛蛛,我...
    開封第一講書人閱讀 39,740評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎胧谈,沒想到半個(gè)月后忆肾,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,286評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡菱肖,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,375評(píng)論 3 340
  • 正文 我和宋清朗相戀三年客冈,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片稳强。...
    茶點(diǎn)故事閱讀 40,505評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡场仲,死狀恐怖和悦,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情渠缕,我是刑警寧澤鸽素,帶...
    沈念sama閱讀 36,185評(píng)論 5 350
  • 正文 年R本政府宣布,位于F島的核電站亦鳞,受9級(jí)特大地震影響馍忽,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜蚜迅,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,873評(píng)論 3 333
  • 文/蒙蒙 一舵匾、第九天 我趴在偏房一處隱蔽的房頂上張望俊抵。 院中可真熱鬧谁不,春花似錦、人聲如沸徽诲。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,357評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽谎替。三九已至偷溺,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間钱贯,已是汗流浹背挫掏。 一陣腳步聲響...
    開封第一講書人閱讀 33,466評(píng)論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留秩命,地道東北人尉共。 一個(gè)月前我還...
    沈念sama閱讀 48,921評(píng)論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像弃锐,于是被迫代替她去往敵國和親袄友。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,515評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容