我正在参加「掘金·启航计划」
本文主要介绍iOS中获取健康中的一些数据的方法
1. HealthKit使用
我们新建项目,之后提供HealthKit
功能
我们在info.plist
中添加权限
-
Privacy - Health Share Usage Description
允许 app 获取健康中的数据 -
Privacy - Health Update Usage Description
允许 app 更新健康中的数据 -
Privacy - Health Records Usage Description
允许 app 记录数据到健康中
我们在使用的地方进行授权
let isSupport = HKHealthStore .isHealthDataAvailable()
如果支持的话我们定义下我们想要获取和写入
的类型,其中有的后面才有的,比如统计洗手的次数就是在iOS14之后
/// 心率
let heartRate = HKQuantityType .quantityType(forIdentifier: .heartRate)
/// 体重
let bodyMass = HKQuantityType .quantityType(forIdentifier: .bodyMass)
/// 高度
let height = HKQuantityType .quantityType(forIdentifier: .height)
/// 步数
let stepCount = HKQuantityType .quantityType(forIdentifier: .stepCount)
/// 睡眠
let sleep = HKObjectType.categoryType(forIdentifier: .sleepAnalysis)
/// 卡路里活动能量
let energy = HKQuantityType.quantityType(forIdentifier: .activeEnergyBurned)
/// 温度
let bodyTemperature = HKQuantityType.quantityType(forIdentifier: .bodyTemperature)
/// 血糖
let bloodGlucose = HKQuantityType.quantityType(forIdentifier: .bloodGlucose)
let set = NSSet(objects: height!,bodyMass!,heartRate!,stepCount!,bodyTemperature!,bloodGlucose!)
var redSet = NSSet(objects: height!,bodyMass!,heartRate!,stepCount!,sleep!,energy!,bodyTemperature!,bloodGlucose!)
if #available(iOS 14.0, *) {
/// 洗手
let handwashing = HKQuantityType.categoryType(forIdentifier: .handwashingEvent)
redSet = NSSet(objects: height!,bodyMass!,heartRate!,stepCount!,sleep!,energy!,handwashing!,bloodGlucose!,bodyTemperature!)
}
我们发送权限请求
let healthStore = HKHealthStore.init()
healthStore.requestAuthorization(toShare: set as? Set<HKSampleType>, read: redSet as? Set<HKObjectType>) { sucess, error in
print(sucess)
}
2. HealthKit数据读取
我们读取类型HKTypeIdentifier
,主要有2种。
- HKQuantityTypeIdentifier
有些我们使用的,我们结合实际情况进行选择
- HKCategoryTypeIdentifier
我在有的HKQuantityTypeIdentifier
没有找到我想要的类型,比如睡眠
CategoryType在未来将会取代,但是目前有的类型还是要通过CategoryType获取
我们定义2个方法来获取不同类型的数据
@objc protocol GetHealthInfoProtocol {
/// 根据类型获取健康信息,比如身高,体重等
@objc optional func getHealthInfoOfQuantityType(type:HKQuantityTypeIdentifier, _ unit:HKUnit?, completion: (@escaping (Double) -> Void));
/// 根据类型获取健康信息,比如身高,体重等
@objc optional func getHealthInfoOfCategoryType(type:HKCategoryTypeIdentifier, _ unit:HKUnit?, completion: (@escaping ([HKSample]) -> Void));
}
具体实现
let healthStore = HKHealthStore()
func getHealthInfoOfCategoryType(type: HKCategoryTypeIdentifier, _ unit:HKUnit?, completion: @escaping (([HKSample]) -> Void)) {
let categoryType = HKQuantityType.categoryType(forIdentifier: type)!
let calendar = Calendar.current
let now = NSDate()
let componsssss :Set<Calendar.Component> = [Calendar.Component.day,Calendar.Component.month,Calendar.Component.year]
var components = calendar.dateComponents(componsssss, from: now as Date)
components.hour = 0
components.minute = 0
components.second = 0
let startDate = calendar.date(from: components)
let endDate = calendar.date(byAdding: Calendar.Component.day, value: 1, to: startDate!)
let predicate = HKQuery.predicateForSamples(withStart: startDate, end: endDate, options: .strictStartDate)
let query = HKSampleQuery.init(sampleType: categoryType,
predicate: predicate,
limit: HKObjectQueryNoLimit,
sortDescriptors: [NSSortDescriptor(key: HKSampleSortIdentifierStartDate, ascending: false)]){ _, results, _ in
guard let result = results else {
return completion([])
}
return completion(result)
}
healthStore.execute(query)
}
这里我们使用HKSampleQuery
进行查询,这个通常是返回一个数组。这里我定义的是一天的时间
- HKStatisticsQuery
let query = HKStatisticsQuery(quantityType: quantityType, quantitySamplePredicate: predicate, options: .cumulativeSum) { _, result, _ in
guard let result = result, let sum = result.sumQuantity() else {
return completion(0.0)
}
let doubleValue = sum.doubleValue(for: unit ?? HKUnit.count())
return completion(doubleValue)
}
healthStore.execute(query)
返回的是HKStatistics
类型:表示一段时间内数量样本的统计信息
3. HealthKit数据写入
也是根据我们type类型定义2种不同的方法
- HKQuantityTypeIdentifier
通过初始化HKQuantitySample
对象,写入我们的数据
/// 保存信息
func saveUserHealthInfoOfCategoryType(type:HKCategoryTypeIdentifier,startDate:Date,endDate:Date,_ unit:HKUnit?,num:Int,completion: (@escaping (Bool) -> Void)) {
let categoryType = HKCategoryType.categoryType(forIdentifier: type)!
let categorySample = HKCategorySample.init(type: categoryType, value: num, start: startDate, end: endDate)
healthStore.save(categorySample) { sucess, error in
completion(sucess)
if sucess {
print("写入数据成功")
}else {
print("写入数据成功")
}
}
}
- HKCategoryTypeIdentifier
初始化HKCategorySample
类型,写入数据
func saveUserHealthInfoOfCategoryType(type:HKCategoryTypeIdentifier,startDate:Date,endDate:Date,_ unit:HKUnit?,num:Int,completion: (@escaping (Bool) -> Void)) {
let categoryType = HKCategoryType.categoryType(forIdentifier: type)!
let categorySample = HKCategorySample.init(type: categoryType, value: num, start: startDate, end: endDate)
healthStore.save(categorySample) { sucess, error in
completion(sucess)
if sucess {
print("写入数据成功")
}else {
print("写入数据成功")
}
}
}
4. 注意
我们这里会有一个时间的选择,获取当天时间
let calendar = Calendar.current
let now = NSDate()
let componsssss :Set<Calendar.Component> = [Calendar.Component.day,Calendar.Component.month,Calendar.Component.year]
var components = calendar.dateComponents(componsssss, from: now as Date)
components.hour = 0
components.minute = 0
components.second = 0
var startDate = calendar.date(from: components)
var endDate = calendar.date(byAdding: Calendar.Component.day, value: 1, to: startDate!)
获取现在时间到之前一天的
Calendar.current.date(byAdding: DateComponents(day: -1), to: Date())!
具体自己调整
let startDate = Calendar.current.date(byAdding: DateComponents(hour: -1,minute: -1,second: -1), to: Date())!
另外我们的HKUnit
类型也是要按规矩的写入,不然崩溃,具体参考,比如心率
HKUnit.init(from: "count/min")
demo展示
代码地址HealthKitDemo