iOS接入HealthKit,获取健康应用步数

Overview

话不多说,先看看官网对HealthKit的解释:

屏幕快照 2018-09-04 15.45.11.png

稍稍翻译一下,创建完成,HealthKit可以完成一下任务:
收集和存储健康和健身数据
分析和可视化数据
实现社交互动

HealthKit中有很多数据,但是没必要全部获取,只需要拿到当前需要的就行。🤦‍♀️

1.启用HealthKit

79f2fd7e-6a9c-4c18-8c70-73ff9b9f992a.png

开启HealthKit之后,在info.plist中增加 Privacy - Health Share Usage DescriptionPrivacy - Health Update Usage Description,内容可以随便填写。

2.确保HealthKit可用

import HealthKit
//检测当前HealthKit是否可以使用
if HKHealthStore.isHealthDataAvailable() {
    print("HealthKit可以使用")
}

3.创建HKHealthStore

let healthStore = HKHealthStore()

4.请求读取和共享数据的权限

//读取权限
let typestoRead = Set([HKObjectType.workoutType(), //步行+跑步距离
                 HKObjectType.quantityType(forIdentifier: .stepCount)!, //步数
                 HKObjectType.quantityType(forIdentifier: .activeEnergyBurned)!,  //活动能量
                 HKObjectType.quantityType(forIdentifier: .distanceCycling)!,  //  骑车距离
                 HKObjectType.quantityType(forIdentifier: .distanceWalkingRunning)!,  // 体能训练
                 HKObjectType.quantityType(forIdentifier: .heartRate)!])  //心率
//写入权限
let typestoShare = Set([
                HKObjectType.quantityType(forIdentifier: .stepCount)!,
                HKObjectType.quantityType(forIdentifier: .activeEnergyBurned)!,
                HKObjectType.quantityType(forIdentifier: .distanceCycling)!,  //活动能量
                HKObjectType.quantityType(forIdentifier: .distanceWalkingRunning)!,
                HKObjectType.quantityType(forIdentifier: .heartRate)!])
healthStore.requestAuthorization(toShare: typestoShare, read: typestoRead, completion: { [weak self] (success, error) in
        if !success {
             NSLog("Display not allowed")
        }else {
             self?.readStep()
        }
})

5.读取数据

func readStep() {
        HKQuantityType.quantityType(forIdentifier: HKQuantityTypeIdentifier.stepCount)
        //NSSortDescriptors用来告诉healthStore怎么样将结果排序
        let start = NSSortDescriptor(key: HKSampleSortIdentifierStartDate, ascending: false)
        let stop  = NSSortDescriptor(key: HKSampleSortIdentifierEndDate, ascending: false)
        let now = Date()
        guard let sampleType = HKSampleType.quantityType(forIdentifier: HKQuantityTypeIdentifier.stepCount) else {
            fatalError("*** This method should never fail ***")
        }
        
        let calendar = Calendar(identifier: Calendar.Identifier.gregorian)
        var dataCom = calendar.dateComponents([.year, .month, .day, .hour, .minute, .second], from: now)
        let endDate = calendar.date(from: dataCom)    //设置查询的截止时间(当前)
        dataCom.hour = 0
        dataCom.minute = 0
        dataCom.second = 0
        let startDate = calendar.date(from: dataCom)    //设置查询的起始时间(当天0点)
        let predicate = HKQuery.predicateForSamples(withStart: startDate, end: endDate, options: HKQueryOptions.strictStartDate)
        
        var localSum: Double = 0  //手机写入步数
        var currentDeviceSum: Double = 0  //软件写入步数
        let query = HKSampleQuery(sampleType: sampleType, predicate: predicate, limit: Int(HKObjectQueryNoLimit), sortDescriptors: [start, stop]) { (query, results, error) in
            
            guard (results as? [HKQuantitySample]) != nil else {
//                fatalError("An error occured fetching the user's tracked food. In your app, try to handle this error gracefully. The error was: \(String(describing: error?.localizedDescription))");
                print("获取步数error ---> \(String(describing: error?.localizedDescription))")
                return
            }
            for res in results! {
                // res.sourceRevision.source.bundleIdentifier  当前数据来源的BundleId
                // Bundle.main.bundleIdentifier  当前软件的BundleId
                if res.sourceRevision.source.bundleIdentifier == Bundle.main.bundleIdentifier {
                    print("app写入数据")
                    let _res = res as? HKQuantitySample
                    currentDeviceSum = currentDeviceSum + (_res?.quantity.doubleValue(for: HKUnit.count()))!
                }else {     //手机录入数据
                    let _res = res as? HKQuantitySample
                    localSum = localSum + (_res?.quantity.doubleValue(for: HKUnit.count()))!
                }
            }
            print("当前步数  -- \(currentDeviceSum)")
            print("当前步数  -- \(localSum)")
//            DispatchQueue.main.async { [weak self] in
//
//            }
        }
        healthStore.execute(query)   //开始查询
    }

6.存入数据

healthStore.requestAuthorization(toShare: typestoShare, read: typestoRead, completion: { [weak self] (success, error) in
                if !success {
                    NSLog("Display not allowed")
                }else {
                    
                    //写入的时间点
                    let now = Date()
                    let startDate = Date(timeInterval: -10, since: now)
                    let countUnit = HKUnit.count()
                    // 写入的步数
                    let countUnitQuantity = HKQuantity.init(unit: countUnit, doubleValue: 1000)
                    let countUnitType = HKQuantityType.quantityType(forIdentifier: HKQuantityTypeIdentifier.stepCount)
                    let stepCountSample = HKQuantitySample.init(type: countUnitType!, quantity: countUnitQuantity, start: startDate, end: now)

                    self?.healthStore.save(stepCountSample) { (isSuccess, error) in
                        if isSuccess {
                            print("保存成功 ----> \(isSuccess)")
                        }else {
                            print("error -----> \(String(describing: error))")
                        }
                    }
                    
                    self?.readStep()
                }
            })

*所有健康数据类型(HKObjectType)

HealthKit使用子类来识别HealthKit中存储的不同类型的数据:HKObjectType

* HKCharacteristicType  表示通常不随时间变化的数据(例如,血型)。
* HKQuantityType 表示包含数值的样本(例如消耗的卡路里)。
* HKCategoryType 表示包含可能值的短列表中的选项的样本(例如睡眠分析)。
* HKCorrelationType 表示包含许多数量或类别样本的复杂样本(例如,包含许多营养样本的食物样本)。
* HKWorkoutType表示锻炼及其相关数据(有关更多信息,请参阅锻炼)。

let bloodType = HKObjectType.characteristicType(forIdentifier: .bloodType)
let caloriesConsumed = HKObjectType.quantityType(forIdentifier: .dietaryEnergyConsumed)
let sleepAnalysis = HKObjectType.categoryType(forIdentifier: .sleepAnalysis)
let food = HKObjectType.correlationType(forIdentifier: .food)

以上是类型,具体可以获取到哪些数据请参考https://developer.apple.com/documentation/healthkit/hkobjecttype

End

当使用了HealthKit的项目提交时,需要注意在 iTunes Connection项目描述中加入项目使用了健康应用数据的提示

demo https://github.com/duke3312/healthKitDemo

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,163评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,301评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,089评论 0 352
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,093评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,110评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,079评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,005评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,840评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,278评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,497评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,667评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,394评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,980评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,628评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,796评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,649评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,548评论 2 352

推荐阅读更多精彩内容