一、HealthKit 简介
HealthKit 是 Apple 在 iOS 8 推出的一款与健康有关的 API ,它提供了一种优雅的方式来获取和存储用户的健康数据。在 iOS 8 Apple 加入了一个健康APP,用来整合不同来源的数据。这些数据包括个人的身高、体重、血型等基本信息,步行+跑步距离、步数等健身信息等。
在本篇 HealthKit 教程中,将会创建一个简单地记录用户信息的 App。主要功能:
- 怎么样向用户请求允许来获得 HealthKit 的数据。
- 怎样通过 HealthKit 获取用户数据,包括获取步数、行走路程、性别。
- 怎么样将数据写回 HealthKit ,如设置体重。
二、HealthKit 准备工作
1、隐私策略
由于苹果一些重要的隐私策略改变,我们需要在info.plist文件中声明苹果健康的使用权限,所以在info.plist中添加以下key就可以了。请求写入和请求读取都需要添加!
1 2 3 4
| <key>NSHealthUpdateUsageDescription</key> NSHealthUpdateUsageDescription <string>请求更新健康信息</string>
|
1 2 3
| <key>NSHealthShareUsageDescription</key> <string>请求获取健康信息</string>
|
2、开启HealthKit
三、HealthKit Let’s Coding
1、代码初始化
新建一个HealthKitManage
类,继承于NSObject
,并且引入HealthKit
库,懒加载healthStore
1 2 3 4
| import HealthKit class HealthKitManage: NSObject { private lazy var healthStore = HKHealthStore() }
|
2、授权
申请获取读取用户的健康信息
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
| private func authorizeHealthKit() { if HKHealthStore.isHealthDataAvailable() { healthStore.requestAuthorization(toShare: dataTypesToWrite(), read: dataTypesRead()) { (isAuthorize, error) in print(isAuthorize) print(error) } } else { print("can't support!") } }
private func dataTypesToWrite() -> Set<HKSampleType>? { guard let height = HKObjectType.quantityType(forIdentifier: .height), let weight = HKObjectType.quantityType(forIdentifier: .bodyMass), let temperature = HKObjectType.quantityType(forIdentifier: .bodyTemperature), let activeEnergy = HKObjectType.quantityType(forIdentifier: .basalEnergyBurned) else { return nil } var set = Set<HKQuantityType>() set.insert(height) set.insert(weight) set.insert(temperature) set.insert(activeEnergy) return set }
private func dataTypesRead() -> Set<HKObjectType>? { guard let height = HKObjectType.quantityType(forIdentifier: .height), let weight = HKObjectType.quantityType(forIdentifier: .bodyMass), let temperature = HKObjectType.quantityType(forIdentifier: .bodyTemperature), let birthday = HKObjectType.characteristicType(forIdentifier: .dateOfBirth), let sex = HKObjectType.characteristicType(forIdentifier: .biologicalSex), let stepCount = HKObjectType.quantityType(forIdentifier: .stepCount), let distance = HKObjectType.quantityType(forIdentifier: .distanceWalkingRunning), let activeEnergy = HKObjectType.quantityType(forIdentifier: .basalEnergyBurned) else { return nil } var set = Set<HKObjectType>() set.insert(height) set.insert(weight) set.insert(temperature) set.insert(birthday) set.insert(sex) set.insert(stepCount) set.insert(distance) set.insert(activeEnergy) return set }
|
3、将HealthKitManage
类,设计为单例
1 2 3 4 5 6
| static let shared = HealthKitManage() private override init() { super.init() authorizeHealthKit() }
|
4、获取步数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
|
func getStepCount(beginTime: Date, endTime: Date, complented: @escaping ((_ step: Int) -> ())) { guard let step = HKObjectType.quantityType(forIdentifier: .stepCount) else { return } let timeSortDescriptor = NSSortDescriptor(key: HKSampleSortIdentifierEndDate, ascending: false) let predicate = HKQuery.predicateForSamples(withStart: beginTime, end: endTime) let query = HKSampleQuery(sampleType: step, predicate: predicate, limit: HKObjectQueryNoLimit, sortDescriptors: [timeSortDescriptor]) { (query, results, error) in guard let results = results as? [HKQuantitySample] else { return } var step = 0 for quantitySample in results { let quantity = quantitySample.quantity let heightUnit = HKUnit.count() let usersHeight = quantity.doubleValue(for: heightUnit) step += Int(usersHeight) } complented(step) } healthStore.execute(query) }
|
5、获取行走路程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
|
func getDistance(beginTime: Date, endTime: Date, complented: @escaping (_ distance: Double) -> ()) { guard let distanceType = HKObjectType.quantityType(forIdentifier: .distanceWalkingRunning) else { return } let timeSortDescriptor = NSSortDescriptor(key: HKSampleSortIdentifierEndDate, ascending: false) let predicate = HKQuery.predicateForSamples(withStart: beginTime, end: endTime) let query = HKSampleQuery(sampleType: distanceType, predicate: predicate, limit: HKObjectQueryNoLimit, sortDescriptors: [timeSortDescriptor]) { (qurry, samples, error) in
guard let quantitySamples = samples as? [HKQuantitySample] else { return } var totalDistance: Double = 0 for quantitySample in quantitySamples { let quantity = quantitySample.quantity let distanceUnit = HKUnit.meterUnit(with: .kilo) let dis = quantity.doubleValue(for: distanceUnit) totalDistance += dis } complented(totalDistance) } healthStore.execute(query) }
|
6、获取性别
1 2 3 4
| func getGender() -> HKBiologicalSex { return (try! healthStore.biologicalSex()).biologicalSex }
|
7、设置体重
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| func setWeight() { let quantityType = HKQuantityType.quantityType(forIdentifier: .bodyMass)! let weight: Double = 0 let quantity = HKQuantity(unit: HKUnit(from: .gram), doubleValue: weight) let weightSample = HKQuantitySample(type: quantityType, quantity: quantity, start: Date(), end: Date()) healthStore.save(weightSample) { (success, error) in if success { print("体重设置成功") } else { print("体重设置失败") } } }
|
四、CoreMotion
如果你修改健康
中的步数,微信健康里的步数并不会改变,说明微信不是用 HealthKit 来获取步数的,有可能是用 CoreMotion 来实现的,这里的数据是无法修改的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| import CoreMotion
class ViewController: UIViewController { private lazy var pedometer = CMPedometer()
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
if !CMPedometer.isStepCountingAvailable() { return } pedometer.queryPedometerData(from: Date(timeIntervalSinceNow: -3 * 24 * 3600), to: Date()) { (data, error) in guard let data = data else { return } print(data) } } }
|
注意:需要在Info.plist中申请权限NSMotionUsageDescription