在HealthKit中用 Swift 進(jìn)行睡眠分析

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

HealthKit

蘋果提供了一種安全奥额、炫酷的方式來顯示用戶的個(gè)人健康信息,并將這些信息安全的存儲(chǔ)在 Health 這個(gè)內(nèi)置的應(yīng)用中访诱。你不僅可以使用 HealthKit 來 創(chuàng)建一個(gè)健身應(yīng)用 垫挨,該框架還允許你訪問睡眠的詳細(xì)數(shù)據(jù)。這本次教程中触菜,我將會(huì)給大家簡(jiǎn)要的介紹 HealthKit 這個(gè)框架九榔,并演示如何創(chuàng)建一個(gè)簡(jiǎn)單的睡眠分析的應(yīng)用。

**簡(jiǎn)介 **


HealthKit 提供了一個(gè)名為 HealthKit store 的結(jié)構(gòu)用來存儲(chǔ)加密的數(shù)據(jù)涡相。你可以使用HKHealthStore這個(gè)類來訪問這個(gè)數(shù)據(jù)庫(kù)哲泊。iPhone 和 Apple Watch 都有自己的 HealthKit store,他們之間的健康數(shù)據(jù)是同步催蝗。需要注意的是切威,在 Apple Watch 上老的數(shù)據(jù)會(huì)被定期的清除以節(jié)省空間。并且 丙号,iPad不支持HealthKit 和 Health 先朦。

如果你想基于健康數(shù)據(jù)創(chuàng)建一個(gè) iOS 或者 watchOS 應(yīng)用,HealthKit 是一個(gè)非常強(qiáng)大的工具犬缨。它被設(shè)計(jì)的目的就是管理廣泛地?cái)?shù)據(jù)源烙无,并且根據(jù)用戶的偏好自動(dòng)地合并不同來源的數(shù)據(jù)。應(yīng)用程序還可以訪問每一條原始數(shù)據(jù)遍尺,并且合并他們截酷。這些數(shù)據(jù)不僅能夠用于身體評(píng)估,健康狀況評(píng)估以及營(yíng)養(yǎng)狀況評(píng)估乾戏,還能夠用于分析睡眠質(zhì)量迂苛。

接下來,我將會(huì)向你展示在 iOS 上如何利用 HealthKit 保存和訪問睡眠數(shù)據(jù)鼓择。這種方法也同樣適合 watchOS 上的應(yīng)用三幻。請(qǐng)注意本次教程使用的是 Swift 2.0 和 Xcode 7。因此呐能,請(qǐng)確保你跟隨此教程的時(shí)候使用的是 Xcode 7(或者以上)念搬。

在此之前,下載最開始的工程 并解壓摆出。我已經(jīng)為你創(chuàng)建了基本功能的用戶界面朗徊。當(dāng)你運(yùn)行這個(gè)工程的時(shí)候,你將會(huì)看到一個(gè)定時(shí)器的 UI 偎漫,當(dāng)你按下開始按鈕以后就會(huì)顯示計(jì)時(shí)爷恳。

** 使用 HealthKit**


我們使用這個(gè)應(yīng)用的目的是使用開始和停止按鈕來保存睡眠分析信息和復(fù)取數(shù)據(jù)。要使用 HealthKit象踊,你必須給你的應(yīng)用授權(quán)温亲。也就是在你的應(yīng)用中棚壁,按著 target -> capabilities -> 打開HealthKit開關(guān) 這個(gè)步驟

HealthKit-allow

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


    let healthStore = HKHealthStore()

隨后我們將使用 HKHealthStore 這個(gè)實(shí)例來訪問 HealthKit store栈虚。

如之前所說袖外, HealthKit 授予用戶權(quán)限來訪問他們的健康數(shù)據(jù)。所以你在獲得用戶的睡眠分析數(shù)據(jù)權(quán)限(讀/寫)之前魂务,你必須現(xiàn)請(qǐng)求用戶的許可在刺。要做到這一點(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)限。在閉包中相艇,你可以對(duì)成功或者失敗進(jìn)行處理颖杏,并得到最終結(jié)果。用戶沒有必要授予你的應(yīng)用所有你請(qǐng)求的權(quán)限坛芽。所以在你的應(yīng)用中你必須妥善的處理這些錯(cuò)誤留储。

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

Health-App-Permission

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


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

  • 用戶進(jìn)入睡眠所花費(fèi)的時(shí)間

  • 用戶在床上的時(shí)間和實(shí)際睡眠時(shí)間的百分比

  • 用戶在床上醒來的次數(shù)

  • 用戶在床上和睡著的時(shí)間的總和

record_sleep_data

簡(jiǎn)單地說,你按照下面的方法來保存你的睡眠分析數(shù)據(jù)到 HealthKit 商店:

  • 1煞烫、我們需要定義兩個(gè) NSDate 的對(duì)象用于開始時(shí)間和結(jié)束時(shí)間浑此。

  • 2、用 HKCategoryTypeIdentifierSleepAnalysis 創(chuàng)建一個(gè) HKObjectType的實(shí)例滞详。

  • 3凛俱、我們需要?jiǎng)?chuàng)建一個(gè)新的HKCategorySample類型的對(duì)象,你通常使用一類的樣本來記錄睡眠時(shí)間料饥,單個(gè)的樣本代表用戶在床上或者在睡覺的時(shí)間段蒲犬。因此,我們將會(huì)創(chuàng)建一個(gè)在床上和一個(gè)睡著了的重疊時(shí)間樣本稀火。

  • 4暖哨、最后赌朋,我們用 HKHealthStoresaveObject 方法來保存上述實(shí)例凰狞。

如果你想用 Swift 實(shí)現(xiàn)上述所有篇裁,這里有保存在床上和睡眠中睡眠分析數(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
            }
            
        })
        
    }
    
}

當(dāng)我們想把睡眠分析數(shù)據(jù)保存到 HealthKit 的時(shí)候上述方法將會(huì)被調(diào)用赡若。

** 讀取睡眠分析數(shù)據(jù)**


要讀取睡眠分析數(shù)據(jù)达布,我們需要?jiǎng)?chuàng)建一個(gè)query。首先你需要用 HKCategoryTypeIdentifierSleepAnalysis 定義一個(gè) HKObjectType類型的實(shí)例逾冬,你可能還需要一個(gè)謂詞來篩選你用開始時(shí)間和結(jié)束時(shí)間復(fù)取的數(shù)據(jù)黍聂,也就是你想要檢索的時(shí)間范圍內(nèi)的 NSDate 類型的對(duì)象。你還需要?jiǎng)?chuàng)建一個(gè) 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é)束時(shí)間或者在睡覺的開始結(jié)束時(shí)間被打印出來。我已經(jīng)設(shè)置了上限30用來檢索最后記錄的30個(gè)樣本嘀趟。你也可以用謂詞的方法來選擇你的自定義開始時(shí)間和結(jié)束時(shí)間脐区。

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


對(duì)于這個(gè) demo,我已經(jīng)使用 NSTimer 來顯示你按下按鈕之后經(jīng)過的時(shí)間她按。當(dāng)開始和結(jié)束按鈕按下的時(shí)候?qū)?huì)創(chuàng)建 NSDate 的對(duì)象來保存所經(jīng)過的時(shí)間作為睡眠分析數(shù)據(jù)牛隅。在停止的方法中,你可以調(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)行這個(gè) demo 然后開始計(jì)時(shí)。讓它運(yùn)行幾分鐘圆丹,然后點(diǎn)擊停止按鈕。然后裂允,打開 Health 這個(gè)應(yīng)用廓旬,你就可以找到你的睡眠數(shù)據(jù)。

sleep-analysis-test

一些關(guān)于 HealthKit 應(yīng)用的建議


HealthKit 旨在提供一個(gè)公共平臺(tái)碘耳,使應(yīng)用程序開發(fā)人員能夠很容易地共享和訪問用戶的數(shù)據(jù)显设,并避免任何可能的重復(fù)或不一致的數(shù)據(jù)。蘋果審核指南對(duì)使用 HealthKit 有很明確的要求辛辨,如果對(duì)用戶的讀/寫權(quán)限請(qǐng)求沒有明確的描述就很可能導(dǎo)致應(yīng)用程序被拒絕捕捂。

應(yīng)用如果保存?zhèn)卧旎蛘咤e(cuò)誤的數(shù)據(jù)到健康應(yīng)用的話也將被拒絕。這就意味著斗搞,你不能像在本次教程中睡眠分析這樣天真的以你的算法計(jì)算不同的健康值指攒。你應(yīng)該嘗試使用內(nèi)置的傳感器數(shù)據(jù)讀取和操作一些參數(shù),以避免計(jì)算錯(cuò)誤。

關(guān)于完整的 Xcode 項(xiàng)目僻焚,你可以在 這里 看到允悦。

原文出處:sing Sleep Analysis in HealthKit with Swift

最后編輯于
?著作權(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
  • 文/不壞的土叔 我叫張陵降淮,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我搏讶,道長(zhǎ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
  • 文/蒼蘭香墨 我猛地睜開眼乳怎,長(zhǎng)吁一口氣:“原來是場(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ú)居荒郊野嶺守林人離奇死亡剃根,尸身上長(zhǎng)有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
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至汁果,卻和暖如春涡拘,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背据德。 一陣腳步聲響...
    開封第一講書人閱讀 33,466評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工鲸伴, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人晋控。 一個(gè)月前我還...
    沈念sama閱讀 48,921評(píng)論 3 376
  • 正文 我出身青樓汞窗,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親赡译。 傳聞我的和親對(duì)象是個(gè)殘疾皇子仲吏,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,515評(píng)論 2 359

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