HealthKit學(xué)習(xí)

HealthKit框架學(xué)習(xí)

本文結(jié)構(gòu)
  • 簡(jiǎn)介
  • 用戶數(shù)據(jù)安全及隱私
  • HealthKit框架介紹
  • HealthKit使用
  • 總結(jié)

簡(jiǎn)介

HealthKit是Apple公司在推出iOS 8 系統(tǒng)時(shí)一塊推出的關(guān)于健康信息的框架拦键。如果iPhone手機(jī)系統(tǒng)升級(jí)到iOS8之后就會(huì)發(fā)現(xiàn)多了一個(gè)健康-app,這就是Apple提供的一個(gè)記錄用戶健康信息的app,可以用它來分享健康和健身數(shù)據(jù)芒涡。還可以指定數(shù)據(jù)的來源鸥跟,比如我們自己創(chuàng)建一個(gè)app,在我們的app中使用了HealthKit框架之后只要經(jīng)過用戶的認(rèn)證奢啥,就可以在我們的app之中給健康分享數(shù)據(jù)或者從健康中獲取數(shù)據(jù)。

HealthKit可以與健身設(shè)備一起工作序攘,iPhone手機(jī)自身可以監(jiān)控步數(shù)信息摇予,會(huì)自動(dòng)導(dǎo)入步數(shù)信息。但是其他信息或者設(shè)備需要配套的應(yīng)該才能獲取到數(shù)據(jù)并導(dǎo)入到HealthKit中并在健康中顯示灵奖。

HealthKit不能再iPad中使用,而且它也不支持?jǐn)U展搬泥。

用戶數(shù)據(jù)安全及隱私

由于用戶的健康信息可能是敏感的桑寨,所以這些用戶信息不能讓開發(fā)者很隨便的獲取到伏尼。每條信息的讀寫都需要用戶去選擇是否同意忿檩,比如用戶可以同意你獲取到用戶的身高體重,但是不同意讀寫生殖健康等其他用戶不愿意公開的信息爆阶。為了防止信息泄露燥透,我們是不知道用戶是否禁止了某條信息是否被用戶禁止讀取的沙咏。簡(jiǎn)單的說,如果獲取不到某條信息班套,就代表沒有這條信息肢藐。

關(guān)于更多的關(guān)于隱私的信息,可以參考隱私

HealthKit框架介紹

HealthKit在各個(gè)應(yīng)用之間提供了一種有意義的方式共享數(shù)據(jù)吱韭。因此吆豹,我們必須使用HealthKit框架提供的數(shù)據(jù)類型和單位。這保證了數(shù)據(jù)存在的真正意義理盆,我們不能自定義數(shù)據(jù)類型及單位痘煤。框架使用了子類化猿规,例如HKObjectHKObjectType抽象類擁有很多有平行關(guān)系的子類衷快,當(dāng)使用Object或者ObjectType的時(shí)候,必須確保使用正確的子類姨俩。

HealthKit中能夠存儲(chǔ)的類都是HKObject的子類蘸拔,大部分HKObject的子類都是不可變的。每個(gè)對(duì)象都有下面的屬性:

  • UUID:每個(gè)對(duì)象的標(biāo)識(shí)符
  • Source:數(shù)據(jù)的來源环葵,來源可以是HealthKit的健康app,也可以是我們自己創(chuàng)建的app调窍。當(dāng)一個(gè)對(duì)象存儲(chǔ)到HealthKit中時(shí)會(huì)設(shè)置其來源。只有從HealthKit中獲取到的數(shù)據(jù)的來源才有效张遭。
  • Metadata:一個(gè)包含該對(duì)象額外信息的字典陨晶,元數(shù)據(jù)包含預(yù)定義的key和自定義的key,預(yù)定義的key用來幫助我們?cè)趹?yīng)用間共享數(shù)據(jù),而自定義的key用來擴(kuò)展HealthKit帝璧,為對(duì)象添加針對(duì)應(yīng)用的數(shù)據(jù)先誉。

HealthKit的對(duì)象主要分為特征和樣本。特征對(duì)象代表用戶的基本不變的數(shù)據(jù)的烁,包括用戶的生日褐耳、血型和性別等。我們創(chuàng)建的app不能修改這些信息渴庆,只能讓用戶在健康中去修改或者添加個(gè)人特征信息铃芦。
樣本對(duì)象代表某個(gè)特定時(shí)間的數(shù)據(jù),所有的樣本類型的對(duì)象都是HKSample的子類襟雷。它們都有下面的特性:

  • Type :樣本類型刃滓,例如:睡眠分享、步行距離耸弄、心率樣本等
  • StartDate:樣本開始時(shí)間
  • EndDate:樣本結(jié)束時(shí)間咧虎。如果是某一個(gè)時(shí)間的樣本,則開始于結(jié)束時(shí)間相同计呈,如果是某個(gè)時(shí)間段的樣本砰诵,則結(jié)束時(shí)間在開始時(shí)間的后面征唬。

樣本類型又可以分為四個(gè)類型:

  1. 類別樣本(HKCategorySample):在iOS 8 中,只有睡眠分析這一個(gè)類別樣本茁彭。代表有限種類的樣本.
  2. 數(shù)量樣本(HKQuantitySample):這種樣本代表存儲(chǔ)數(shù)據(jù)的樣本总寒,比如步數(shù)、距離理肺、用戶的體溫等摄闸。它是HealthKit中最常見的數(shù)據(jù)類型。
  3. 關(guān)系樣本(HKCorrelation):代表復(fù)合數(shù)據(jù)妹萨,包括一個(gè)或者多個(gè)樣本贪薪。在iOS 8 中,用correlation代表食物和血壓眠副。在創(chuàng)建食物或血壓時(shí)画切,需要用correlation
  4. 訓(xùn)練活動(dòng)(HKWorkout):代表某種活動(dòng)囱怕,比如走霍弹、跑步等。包含有開始時(shí)間娃弓、結(jié)束時(shí)間典格、運(yùn)動(dòng)類型、消耗能量台丛、運(yùn)動(dòng)距離等屬性耍缴。還可以為workout關(guān)聯(lián)許多詳細(xì)的樣本。不像correlation挽霉,這些樣本不包含在workout中防嗡,但是可以通過workout獲取到。

再介紹一個(gè)HealthKit中經(jīng)常用到的一些類侠坎。

HKSamle

每個(gè)HkSample的子類都有對(duì)應(yīng)的便利方法創(chuàng)建對(duì)應(yīng)的對(duì)象蚁趁。比如:

對(duì)于數(shù)量樣本,需要?jiǎng)?chuàng)建HKQuantity類的實(shí)例实胸。而且數(shù)量的單位和類型標(biāo)識(shí)符文檔中描述的可用單位要相同他嫡。例如:HKQuantityTypeIdentifierHeight 文檔中說明它使用長(zhǎng)度單位,因此庐完,你的數(shù)量必須使用厘米钢属、米、英尺门躯、英寸或者其他長(zhǎng)度單位淆党。

1.png

對(duì)應(yīng)類別樣本,需要?jiǎng)?chuàng)建HKCategorySample的實(shí)例。它的值必須和類型標(biāo)識(shí)符文檔中描述的枚舉值相關(guān)宁否。例如窒升, HKCategoryTypeIdentifierSleepAnalysis 文檔中說明它使用的枚舉值缀遍。因此你在創(chuàng)建樣本時(shí)必須從這個(gè)枚舉中傳遞一個(gè)值慕匠。

2.png

同樣,你必須先創(chuàng)建correlation包含的所有樣本域醇。correlation的類型標(biāo)識(shí)符描述了它可以包含的類型和對(duì)象的數(shù)量台谊。不要把被包含的對(duì)象存進(jìn)HealthKit。它們是以correlation的一部分存儲(chǔ)的譬挚。

3.png

對(duì)于訓(xùn)練活動(dòng)樣本锅铅,首先,創(chuàng)建 HKWorkoutType 實(shí)例并不需要指定類型標(biāo)識(shí)符减宣。所有的workout都是用同樣的類型標(biāo)識(shí)符盐须。第二,對(duì)于每個(gè)workout你都需要提供一個(gè) HKWorkoutActivityType 值漆腌。這個(gè)值定義了workout中執(zhí)行的活動(dòng)的類型贼邓。最后,當(dāng)workout保存到HealthKit后闷尿,你可以給workout關(guān)聯(lián)額外的樣本塑径。這些樣本提供了workout的詳細(xì)信息。

4.png

HKQuery

HealthKit提供了許多查詢讀取數(shù)據(jù)的方法:

  1. 直接方法查詢填具。對(duì)于特征樣本统舀,可以直接查詢獲取到,這些方法只能查詢特征樣本劳景。更多信息: HKHealthStore Class Reference

  2. 樣本查詢誉简。這是使用最多的查詢。使用樣本查詢可以查詢?cè)贖ealthKit中任意的數(shù)據(jù)盟广。而且可以對(duì)結(jié)果進(jìn)行排序等描融。更多信息:HKSampleQuery Class Reference

  3. 觀察者查詢。這是一個(gè)長(zhǎng)時(shí)間運(yùn)行的查詢衡蚂,它會(huì)檢測(cè)HealthKit存儲(chǔ)窿克,并在匹配到的樣本發(fā)生變化時(shí)通知你。如果當(dāng)存儲(chǔ)發(fā)生變化時(shí)你想得到通知毛甲,就使用觀察者查詢年叮。更多信息:HKObserverQuery Class Reference

  4. 錨定對(duì)象查詢。用這種查詢來搜索添加進(jìn)存儲(chǔ)的項(xiàng)玻募。當(dāng)錨定查詢第一次執(zhí)行時(shí)只损,會(huì)返回存儲(chǔ)中所有匹配的樣本。在接下來的執(zhí)行中,只會(huì)返回上一次執(zhí)行之后添加的項(xiàng)目跃惫。通常叮叹,錨定對(duì)象查詢會(huì)和觀察者查詢一起使用。觀察者查詢告訴你某些項(xiàng)目發(fā)生了變化爆存,而錨定對(duì)象查詢來決定有哪些(如果有的話)項(xiàng)目被添加進(jìn)了存儲(chǔ)蛉顽。更多信息:HKAnchoredObjectQuery Class Reference

  5. 統(tǒng)計(jì)查詢。使用這種查詢來在一系列匹配的樣本中執(zhí)行統(tǒng)計(jì)運(yùn)算先较。你可以使用統(tǒng)計(jì)查詢來計(jì)算樣本的總和携冤、最小值、最大值或平均值闲勺。更多信息: HKStatisticsQuery Class Reference

  6. 統(tǒng)計(jì)集合查詢曾棕。使用這種查詢來在一系列長(zhǎng)度固定的時(shí)間間隔中執(zhí)行多次統(tǒng)計(jì)查詢。通常使用這種查詢來生成圖表菜循。查詢提供了一些簡(jiǎn)單的方法來計(jì)算某些值翘地,例如,每天消耗的總熱量或者每5分鐘行走的步數(shù)癌幕。統(tǒng)計(jì)集合查詢是長(zhǎng)時(shí)間運(yùn)行的衙耕。查詢可以返回當(dāng)前的統(tǒng)計(jì)集合,也可以監(jiān)測(cè)HealthKit存儲(chǔ)序芦,并對(duì)更新做出響應(yīng)臭杰。更多信息,參見 HKStatisticsCollectionQuery Class Reference谚中。

  7. Correlation查詢渴杆。使用這種查詢來在correlation查找數(shù)據(jù)。這種查詢可以為correlation中每個(gè)樣本類型包含獨(dú)立的謂詞宪塔。如果你只是想匹配correlation類型磁奖,那么請(qǐng)使用樣本查詢。更多信息某筐,參見 HKCorrelation Class Reference比搭。

  8. 來源查詢。使用這種查詢來查找HealthKit存儲(chǔ)中的匹配數(shù)據(jù)的來源(應(yīng)用和設(shè)備)南誊。來源查詢會(huì)列出儲(chǔ)存的特定樣本類型的所有來源身诺。更多信息,參見HKSourceQuery Class Reference抄囚。

HKUnit

這個(gè)類代表要查詢的數(shù)據(jù)的單位的類霉赡,比如體重的單位,可以為kg幔托、lbs等穴亏。這個(gè)類為不同的數(shù)據(jù)類型提供了不同的單位方法蜂挪。一般在創(chuàng)建前面介紹的樣本類型的時(shí)候,都需要這個(gè)類為樣本添加對(duì)應(yīng)的單位嗓化。而且提供了一些數(shù)學(xué)運(yùn)算棠涮,比如千米、米刺覆、厘米等之間的轉(zhuǎn)換严肪。

在某些場(chǎng)合,你可以使用格式化器來本地化數(shù)量隅津。iOS8提供了提供了新的格式化器來處理長(zhǎng)度(NSLengthFormatter)诬垂、質(zhì)量(NSMassFormatter)和能量(NSEnergyFormatter)劲室。對(duì)于其他的數(shù)量伦仍,你需要自己來?yè)Q算單位和本地化數(shù)據(jù)。

HKHeathStore

HealthKit的核心就是它很洋,它代表HealthKit的數(shù)據(jù)庫(kù)充蓝,使用它就可以從數(shù)據(jù)庫(kù)中讀取數(shù)據(jù)。比較重要的方法:

  • isHealthDataAvailable:判斷當(dāng)前設(shè)置是否支持HealthKit
  • requestAuthorizationToShareTypes(typesToShare: Set<HKSampleType>?, readTypes typesToRead: Set<HKObjectType>?, completion: (Bool, NSError?) -> Void): 向用戶請(qǐng)求同意讀寫某些數(shù)據(jù)
  • saveObject(object: HKObject, withCompletion completion: (Bool, NSError?) -> Void) :向數(shù)據(jù)庫(kù)中添加數(shù)據(jù)
  • executeQuery(query: HKQuery) :執(zhí)行查詢喉磁,即上面介紹的幾種查詢方法谓苟。

HealthKit使用

在使用HealthKit之前,必須要執(zhí)行下列步驟:

  1. 打開HealthKit,在Target欄中协怒,打開Capabilities菜單涝焙,將HealthKit這一項(xiàng)的開關(guān)設(shè)為ON的狀態(tài)。

  2. 創(chuàng)建HeathManager.Swift 文件孕暇,并導(dǎo)入

     `import HealthKit`
    

    HealthKit的核心是HeathStore仑撞,創(chuàng)建

     func authorizeHealthKit(completion:((success:Bool,error:NSError!)->Void)!){}
    

    然后調(diào)用在這個(gè)方法中調(diào)用isHealthDataAvailable判斷當(dāng)前設(shè)備是否支持HealthKit

     //判斷當(dāng)前設(shè)備是否支持
     if !HKHealthStore.isHealthDataAvailable(){
         let error = NSError(domain: "", code: 2, userInfo: [NSLocalizedDescriptionKey:"HealthKit is not available in this Device"])
         if completion != nil {
             completion(success: false, error: error)
         }
     }
    

    ,最后在上面的方法中妖滔,設(shè)置要讀寫的數(shù)據(jù)類型隧哮。

  3. 為你的應(yīng)用實(shí)例化一個(gè) HKHealthStore 對(duì)象。每個(gè)應(yīng)用只需要一個(gè)HealthKit存儲(chǔ)實(shí)例座舍。這個(gè)存儲(chǔ)實(shí)例就是你和HealthKit數(shù)據(jù)庫(kù)交互的主要接口沮翔。

     let hkHealthStore = HKHealthStore()
    
  4. 使用 requestAuthorizationToShareTypes:readTypes:completion:來認(rèn)證請(qǐng)求從HealthKit獲取數(shù)據(jù)的權(quán)限。

     //請(qǐng)求連接
     hkHealthStore.requestAuthorizationToShareTypes(healthKitTypesToWrite as? Set<HKSampleType>, readTypes: healthKitTypesToRead as? Set<HKObjectType>) { (success, error) -> Void in
         
         if completion != nil{
             completion(success:success,error:error)
         }
         return 
     }
    

    如果當(dāng)前設(shè)備支持HealthKit的時(shí)候曲秉,這樣就會(huì)彈出一個(gè)請(qǐng)求界面采蚀,讓用戶選擇是否同意你能夠獲取到你要請(qǐng)求的數(shù)據(jù)。

獲取特征信息

我們首先創(chuàng)建了ProfileViewController.swift,并用IB創(chuàng)建一個(gè)請(qǐng)求個(gè)人信息的界面

5.png

然后在HeathManager.Swift 文件中添加請(qǐng)求個(gè)人信息的方法承二。
對(duì)于請(qǐng)求特征信息榆鼠,前提上用戶通過健康添加了出生日期、性別矢洲、血型等特征信息

func readProfile()->(age:Int?,biologicalsex:HKBiologicalSexObject?,bloodType:HKBloodTypeObject?){
    
    //請(qǐng)求年齡
    var age:Int?
    let birthDay:NSDate;
    do {
        birthDay = try hkHealthStore.dateOfBirth()
        let today = NSDate()
        let diff = NSCalendar.currentCalendar().components(.Year, fromDate: birthDay, toDate: today, options: NSCalendarOptions(rawValue: 0))
        age = diff.year
    }catch {
        
    }
    //請(qǐng)求性別
    var biologicalSex
    :HKBiologicalSexObject?
    do {
        biologicalSex  = try hkHealthStore.biologicalSex()
        
    }catch {
        
    }    
    //請(qǐng)求血型
    var hkbloodType:HKBloodTypeObject?
    
    do {
        hkbloodType = try hkHealthStore.bloodType()
    }catch{
        
    }
    
    return (age,biologicalSex,hkbloodType)
}

請(qǐng)求體重璧眠、身高、BMI的時(shí)候,創(chuàng)建另外的方法责静。

func fetchMostRecentSample(sample:HKSampleType,competion:((HKSample!,NSError!)->Void)!){
    //1.創(chuàng)建謂詞
    let past = NSDate.distantPast()
    let now = NSDate()
    let mostRecentPredicate = HKQuery.predicateForSamplesWithStartDate(past, endDate: now, options: .None)
    
    //2.創(chuàng)建返回結(jié)果排序的描述袁滥,是降序還是升序的,因?yàn)橹恍枰粋€(gè)結(jié)果灾螃,就設(shè)定限制為1個(gè)
    let sortDescrptor = NSSortDescriptor(key:HKSampleSortIdentifierStartDate , ascending: false)
    let limit = 1
    
    //3.創(chuàng)建HKSampleQuery對(duì)象题翻,
    let sampleQuery = HKSampleQuery(sampleType: sample, predicate: mostRecentPredicate, limit: limit, sortDescriptors: [sortDescrptor]) { (sampleQuery, results, error) -> Void in
        
        if let queryError = error {
            competion(nil,queryError)
            return
        }
        
        let mostRecentSample = results?.first
        
        if competion != nil{
            competion(mostRecentSample,nil)
        }
        
    }
    
    //4.執(zhí)行查詢
    self.hkHealthStore.executeQuery(sampleQuery)
}

獲取之后在之前創(chuàng)建的ProfileViewController.swift文件中獲取這些信息,并更新UI腰鬼。

對(duì)應(yīng)特征信息嵌赠,可以直接調(diào)用查詢方法,并更新

    let  profile = healthManager?.readProfile()
    self.healthStore = HKHealthStore()
    
    ageLabel.text = profile?.age == nil ? kUnKnowString:String(profile!.age!)
    sexLabel.text = biologicSexLiteral(profile?.biologicalsex?.biologicalSex)
    bloodTypeLabel.text = bloodTypeLiteral(profile?.bloodType?.bloodType)

這里面創(chuàng)建了兩個(gè)工具方法biologicSexLiteralbloodTypeLiteral來修改查詢的結(jié)果為我們想要的樣子并顯示在界面上熄赡。

對(duì)于體重和身高姜挺,需要?jiǎng)?chuàng)建樣本查詢

/**
 獲取并更新體重
 */
func updateWeight(){ 
    let weightSampleType = HKSampleType.quantityTypeForIdentifier(HKQuantityTypeIdentifierBodyMass)
    self.healthManager?.fetchMostRecentSample(weightSampleType!, competion: { (mostRecentSample, error) -> Void in
        
        if error != nil {
            return
        }
        
        var weightString = self.kUnKnowString
        self.weight = mostRecentSample as? HKQuantitySample
        
        //根據(jù)我們想要的數(shù)據(jù)類型單位獲取對(duì)應(yīng)的結(jié)果
        if let kilograms = self.weight?.quantity.doubleValueForUnit(HKUnit.gramUnitWithMetricPrefix(HKMetricPrefix.Kilo)){
            //體重格式化
            let weightFommater = NSMassFormatter()
            weightFommater.forPersonMassUse = true
            weightString = weightFommater.stringFromKilograms(kilograms)
        }
        
        //因?yàn)檫@個(gè)查詢默認(rèn)是異步查詢的,所以需要在主線程更新UI
        dispatch_async(dispatch_get_main_queue()) { () -> Void in
            self.weightLabel.text = weightString
            self.updateBMILabel()
        }
        
    })
}

/**
 獲取并更新身高
 */
func updateHeight(){
    //設(shè)置要查找的類型彼硫,根據(jù)標(biāo)識(shí)符
    let heightSampleType = HKSampleType.quantityTypeForIdentifier(HKQuantityTypeIdentifierHeight)
    
    //獲取身高樣本
    self.healthManager?.fetchMostRecentSample(heightSampleType!, competion: { (heightSample, error) -> Void in
        
        if error != nil {
            return
        }
        
        var heightStr = self.kUnKnowString
        self.height = heightSample as? HKQuantitySample
        
        //根據(jù)我們想要的數(shù)據(jù)類型單位獲取對(duì)應(yīng)的結(jié)果
        if let kilograms =  self.height?.quantity.doubleValueForUnit(HKUnit.meterUnit()){
            
            heightStr = String(format: "%.2f", kilograms) + "m"
        }
        
        //因?yàn)檫@個(gè)查詢默認(rèn)是異步查詢的炊豪,所以需要在主線程更新UI
        dispatch_async(dispatch_get_main_queue()) { () -> Void in
            self.heightLabel.text = heightStr
            self.updateBMILabel()
        }
        
    })
}

對(duì)應(yīng)BMI,它代表人的身體質(zhì)量指數(shù),它的計(jì)算方式是:體重/(身高*身高)拧篮。因此它可以這樣獲得

/**
 獲取并設(shè)置BMI:
 */
func updateBMILabel(){
    
    //根據(jù)我們想要的數(shù)據(jù)類型單位獲取對(duì)應(yīng)的結(jié)果
    let weight = self.weight?.quantity.doubleValueForUnit(HKUnit.gramUnitWithMetricPrefix(HKMetricPrefix.Kilo))
    let height = self.height?.quantity.doubleValueForUnit(HKUnit.meterUnit())
    var bmiValue = 0.0
    if height == 0{
        
        return
    }
 
    dispatch_async(dispatch_get_main_queue()) { () -> Void in
        bmiValue = (weight!)/(height! * height!)
        self.BMILabel.text = String(format: "%.02f", bmiValue)
    } 
}

添加BMI到HeathStore

在下面的方法中添加一個(gè)alertView讓用戶輸入BMI值词渤,然后點(diǎn)擊確認(rèn)按鈕之后添加到HeathStore

@IBAction func addBMIData2HealthStore(sender: AnyObject) {        
    let alertView = UIAlertController(title: "輸入BMI值", message: nil, preferredStyle: .Alert)
    
    alertView.addTextFieldWithConfigurationHandler { (textField) -> Void in
        textField.keyboardType = .NumberPad
    }
    
    let action =  UIAlertAction(title: "添加", style: .Default) { (action) -> Void in
        
        var value:Double?
        
        if let text = alertView.textFields?.first?.text {
            if text.characters.count > 0 {
                value = Double(text)
                self.saveBMI2HealthStore(value!)
            }
        }
    }
    alertView.addAction(action)
    
    self .presentViewController(alertView, animated: true, completion: nil)
}


//保存BMI到HealthKitStore中
func saveBMI2HealthStore(height:Double){
    
    //BMI的類型
    let BMIType =  HKQuantityType.quantityTypeForIdentifier(HKQuantityTypeIdentifierBodyMassIndex)
    
    //根據(jù)標(biāo)識(shí)符對(duì)應(yīng)的單位創(chuàng)建BMI的數(shù)量對(duì)象
    let BMIQuantity = HKQuantity(unit: HKUnit.countUnit(), doubleValue: height)
    
    let now = NSDate()
    
    //根據(jù)起止時(shí)間以及上面創(chuàng)建的創(chuàng)建HKQuantity對(duì)象創(chuàng)建數(shù)量樣本
    let BMISample =  HKQuantitySample(type: BMIType!, quantity: BMIQuantity, startDate: now, endDate: now)
    
    //保存數(shù)量樣本到healthStore中
    self.healthStore?.saveObject(BMISample, withCompletion: { (success, error) -> Void in
        
        if success {
            print("添加成功")
            self.updateWeight()
        }
        
        if (error != nil) {
            print("添加失敗")
        }
    })
}

如果添加成功,你就可以去手機(jī)上的健康查找BMI串绩,就可以看到我們剛才添加的BMI值缺虐,而且它的來源是我們創(chuàng)建的app。

獲取HKWorkout

創(chuàng)建一個(gè)WorkOutsViewController.swift文件礁凡,并在SB中拖對(duì)應(yīng)的IB文件高氮,界面如下

6.png

然后在在HeathManager.Swift 文件中添加請(qǐng)求workout的方法

/**
 獲取workoutData
 */
func fetchWorkOutsData(completion:([AnyObject]!,NSError!)->Void){
    
    let workOutsSampleType = HKSampleType.workoutType()
    
    let workOutsPredicate = HKQuery.predicateForWorkoutsWithWorkoutActivityType(.Running)
    
    let sortDescrptor = NSSortDescriptor(key:HKSampleSortIdentifierStartDate , ascending: false)
    
    let workOutsQuery = HKSampleQuery(sampleType: workOutsSampleType, predicate: workOutsPredicate, limit: 0, sortDescriptors: [sortDescrptor]) { (workoutsQuery, results, error) -> Void in
        
        if (error != nil){
            print("獲取失敗")
            return
        }
        
        if results != nil{
            completion(results!,nil)
        }
        
    }
    
    self.hkHealthStore.executeQuery(workOutsQuery)
    
}

然后在WorkOutsViewController.swift文件的viewWillAppear()方法中請(qǐng)求workout

self.healthManager?.fetchWorkOutsData({ (results, error) -> Void in
        
        if error != nil{
            print("獲取失敗")
        }else{
            self.workOuts = results as! [HKWorkout]
        }
        
        dispatch_async(dispatch_get_main_queue(), { () -> Void in
            self.tableView.reloadData()
        });
    })

最后在tableView顯示如下

7.png

保存HKWorkout

在上面的界面的NavgationBar的rightBarItem向下再拖一個(gè)控制器,并添加對(duì)應(yīng)的文件AddWorkoutsViewController.swift把篓,并在IB中設(shè)置界面信息如下

8.png

然后在 AddWorkoutsViewController.swift 復(fù)寫 tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath),針對(duì)點(diǎn)擊不同的cell纫溃,執(zhí)行不同的方法。即讓用戶輸入點(diǎn)擊的cell對(duì)應(yīng)的輸入方式韧掩,比如時(shí)間就是時(shí)間選擇器紊浩。距離就是一個(gè)警示框加一個(gè)文本框等。

override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
    
    tableView.deselectRowAtIndexPath(indexPath, animated: true)
    
    self.tableView.tableFooterView = UIView()
    
    switch indexPath.row{
        
    case 0:
        self.setupPickerView()
        
    case 1,2:
        self.setupDatePickerView(indexPath.row)
        
    case 3,4:
        self.setupAlertView(indexPath.row)
    default:
        break
    }
}

這里面對(duì)應(yīng)的選擇的方法就不一一介紹了疗锐,就是幾個(gè)普通的view的添加坊谁。添加完所有的信息之后就可以點(diǎn)擊done 保存信息,方法如下:

    @IBAction func addWorkOut(sender: AnyObject) {
    
    self.heathStore = HKHealthStore()
    
    //獲取距離和能量的數(shù)值
    let distanceValue = Double(self.distanceLabel.text!)
    let energyValue = Double(self.energyLabel.text!)
    
    //根據(jù)上面的數(shù)值創(chuàng)建對(duì)應(yīng)的HKQuantity對(duì)象
    let distance = HKQuantity(unit: HKUnit.mileUnit(), doubleValue: distanceValue!)
    let energy = HKQuantity(unit: HKUnit.calorieUnit(), doubleValue: energyValue!)
    
    let endDate = self.dateFommater?.dateFromString(self.endDateLabel.text!)
    let startDate = self.dateFommater?.dateFromString(self.startDateLabel.text!)
    
    //這里我默認(rèn)設(shè)置成running了滑臊】谏郑可以根據(jù)具體的類型再進(jìn)行設(shè)置。
    //創(chuàng)建HKWorkout對(duì)象雇卷。
    let workout = HKWorkout(activityType: .Running, startDate: startDate!, endDate: endDate!, workoutEvents: nil, totalEnergyBurned: energy, totalDistance: distance, metadata: nil)
    
    //保存上面創(chuàng)建的HKWorkout對(duì)象
    self.heathStore?.saveObject(workout, withCompletion: { (success, error) -> Void in
        if error != nil{
            print("添加錯(cuò)誤")
            return
        }
        
        if success{
            print("添加成功")
            dispatch_async(dispatch_get_main_queue(), { () -> Void in
                self.dismissViewControllerAnimated(true, completion: nil)
            })
        }
        
    })
}

如果上面都執(zhí)行成功鬓椭,AddWorkoutsViewController.swift就會(huì)模態(tài)消失颠猴,然后在上面的一個(gè)頁(yè)面``WorkOutsViewController.swift就會(huì)在tableView的最上層顯示出我們剛才添加成功的HKWorkout`

總結(jié)

在本人過完春節(jié)回到公司上班之后經(jīng)理問我健康app里面的信息能不能獲取到。之前只是簡(jiǎn)單了解了這個(gè)框架小染,但是里面的具體結(jié)構(gòu)體系并不了解翘瓮。就趁著項(xiàng)目不忙,抽空把HealthKit學(xué)習(xí)了解了一下裤翩。本文的demo也采用了之前自學(xué)的Swift簡(jiǎn)單的實(shí)現(xiàn)了一下(屬于Switer新手)资盅。可能會(huì)有錯(cuò)誤或不準(zhǔn)確的地方踊赠,如果你看到了呵扛,可以給我聯(lián)系ls_xyq@126.com,我會(huì)及時(shí)更改的筐带。寫這篇文章一是對(duì)HealthKit的學(xué)習(xí)的一個(gè)練習(xí)今穿,在這也是給以后會(huì)用到的童鞋一個(gè)可以參考的東西。

HealthKit不只是上面的這些內(nèi)容烫堤,但是能把上面的這些問題搞定荣赶,我覺得針對(duì)HealthKit的體系會(huì)有一個(gè)清楚的認(rèn)識(shí)凤价,學(xué)習(xí)HealthKit更深層次的內(nèi)容會(huì)有很大的幫助鸽斟。

本文的demo已經(jīng)放到github上面,需要的同學(xué)可以下載看看利诺。

本文參考文章:

  1. HealthKit框架參考
  2. HealthKit開發(fā)教程Swift版
  3. The HealthKit Framework
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末富蓄,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子慢逾,更是在濱河造成了極大的恐慌立倍,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,968評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件侣滩,死亡現(xiàn)場(chǎng)離奇詭異口注,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)君珠,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門寝志,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人策添,你說我怎么就攤上這事材部。” “怎么了唯竹?”我有些...
    開封第一講書人閱讀 153,220評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵乐导,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我浸颓,道長(zhǎng)物臂,這世上最難降的妖魔是什么旺拉? 我笑而不...
    開封第一講書人閱讀 55,416評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮棵磷,結(jié)果婚禮上账阻,老公的妹妹穿的比我還像新娘。我一直安慰自己泽本,他們只是感情好淘太,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,425評(píng)論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著规丽,像睡著了一般蒲牧。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上赌莺,一...
    開封第一講書人閱讀 49,144評(píng)論 1 285
  • 那天冰抢,我揣著相機(jī)與錄音,去河邊找鬼艘狭。 笑死挎扰,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的巢音。 我是一名探鬼主播遵倦,決...
    沈念sama閱讀 38,432評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼官撼!你這毒婦竟也來了梧躺?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,088評(píng)論 0 261
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤傲绣,失蹤者是張志新(化名)和其女友劉穎掠哥,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體秃诵,經(jīng)...
    沈念sama閱讀 43,586評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡续搀,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,028評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了菠净。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片禁舷。...
    茶點(diǎn)故事閱讀 38,137評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖嗤练,靈堂內(nèi)的尸體忽然破棺而出榛了,到底是詐尸還是另有隱情,我是刑警寧澤煞抬,帶...
    沈念sama閱讀 33,783評(píng)論 4 324
  • 正文 年R本政府宣布霜大,位于F島的核電站,受9級(jí)特大地震影響革答,放射性物質(zhì)發(fā)生泄漏战坤。R本人自食惡果不足惜曙强,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,343評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望途茫。 院中可真熱鬧碟嘴,春花似錦、人聲如沸囊卜。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)栅组。三九已至雀瓢,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間玉掸,已是汗流浹背刃麸。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評(píng)論 1 262
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留司浪,地道東北人泊业。 一個(gè)月前我還...
    沈念sama閱讀 45,595評(píng)論 2 355
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像啊易,于是被迫代替她去往敵國(guó)和親吁伺。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,901評(píng)論 2 345

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

  • The HealthKit Framework[https://developer.apple.com/libra...
    可愛的活火山閱讀 9,401評(píng)論 0 11
  • [iOS] HealthKit 獲取步數(shù) 前言 HealthKit 是蘋果在 iOS 8.0 之后推出的健康框架认罩,...
    李小六_閱讀 1,351評(píng)論 0 7
  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫(kù)箱蝠、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 12,029評(píng)論 4 62
  • “我是一座離島牙瓢,人海邊的離島”劫拗,這是田馥甄《離島》里的一句歌詞。也是能唱出我的現(xiàn)狀的一句歌詞矾克。 那個(gè)時(shí)候還小页慷,音樂...
    南邊離島閱讀 1,086評(píng)論 0 0
  • 見我臉色不好,同桌就把她的鈦合金手機(jī)在我眼前晃晃胁附。我打了個(gè)哈欠酒繁,并未理會(huì)她。一個(gè)上午控妻,早讀州袒、數(shù)學(xué)、物理……在各個(gè)老...
    Chosing_春幸閱讀 334評(píng)論 1 2