Apple Watch 上的心率数据
Heart Rate data on apple Watch
我们可以直接从 Apple Watch 获取心率吗?我知道这是一个重复的问题,但在 5 个月内没有人问过这个问题。我知道您可以从健康应用程序访问它,但我不确定 "real-time" 会怎样。
无法直接访问 Apple Watch 上的任何传感器。您将不得不依赖 HealthKit 的访问权限。
苹果传道者这样说
It is not possible to create a heart monitor app at this time. The
data isn't guaranteed to be sent to iPhone in real-time, so you won't
be able to determine what's going on in any timely fashion.
心率原始数据信息 现已在 Watchkit for watchOS 2.0
中可用。
WatchOS 2
包括对其他现有框架的许多增强,例如 HealthKit
,允许访问实时访问心率和健康信息的健康传感器。
你可以在后面的session里查看这个信息,总共30分钟presentation.If你不想看整个session,那么你直接跳到Healthkit API
features,它在25- 28 分钟:
WatchKit for watchOS 2.0 Session in WWDC 2015
这里是源码实现link
如 HKWorkout Class Reference 中所述:
The HKWorkout
class is a concrete subclass of the HKSample
class.
HealthKit
uses workouts to track a wide range of activities. The
workout object not only stores summary information about the activity
(for example, duration, total distance, and total energy burned), it
also acts as a container for other samples. You can associate any
number of samples with a workout. In this way, you can add detailed
information relevant to the workout.
在给定link的情况下,以下代码部分定义了heartRate
的采样率
NSMutableArray *samples = [NSMutableArray array];
HKQuantity *heartRateForInterval =
[HKQuantity quantityWithUnit:[HKUnit unitFromString:@"count/min"]
doubleValue:95.0];
HKQuantitySample *heartRateForIntervalSample =
[HKQuantitySample quantitySampleWithType:heartRateType
quantity:heartRateForInterval
startDate:intervals[0]
endDate:intervals[1]];
[samples addObject:heartRateForIntervalSample];
正如他们所说:
You need to fine tune the exact length of your associated samples
based on the type of workout and the needs of your app. Using 5 minute
intervals minimizes the amount of memory needed to store the workout ,
while still providing a general sense of the change in intensity over
the course of a long workout. Using 5 second intervals provides a
much-more detailed view of the workout, but requires considerably more
memory and processing.
在探索 HealthKit 和 WatchKit Extension 之后,我的发现如下:
我们不需要 WatchKit 扩展来获取心率数据。
您只需要 iPhone 与配对的 Apple Watch(这很明显)
默认的 Apple Watch 心率监测应用仅在前台运行时才立即更新 HealthKit 数据。
当默认的 Apple Watch 心率监测应用程序在后台运行时,它会以 9-10 分钟的间隔更新 HealthKit 数据。
要从 HealthKit 获取心率数据,需要定期触发以下查询。
func getSamples() {
let heathStore = HKHealthStore()
let heartrate = HKQuantityType.quantityType(forIdentifier: .heartRate)
let sort: [NSSortDescriptor] = [
.init(key: HKSampleSortIdentifierStartDate, ascending: false)
]
let sampleQuery = HKSampleQuery(sampleType: heartrate!, predicate: nil, limit: 1, sortDescriptors: sort, resultsHandler: resultsHandler)
heathStore.execute(sampleQuery)
}
func resultsHandler(query: HKSampleQuery, results: [HKSample]?, error: Error?) {
guard error == nil else {
print("cant read heartRate data", error!)
return
}
guard let sample = results?.first as? HKQuantitySample else { return }
// let heartRateUnit: HKUnit = .init(from: "count/min")
// let doubleValue = sample.quantity.doubleValue(for: heartRateUnit)
print("heart rate is", sample)
}
如果有人得到更多信息,请更新我。
快乐编码。
更新
我已将您的代码更新为清晰和通用,请注意您需要获得授权才能读取 HeathKit 数据和添加 info.plist
密钥 Privacy - Health Records Usage Description
您可以通过开始运动获取心率数据,在healthkit中查询心率数据。
请求阅读锻炼数据的权限。
HKHealthStore *healthStore = [[HKHealthStore alloc] init];
HKQuantityType *type = [HKQuantityType quantityTypeForIdentifier:HKQuantityTypeIdentifierHeartRate];
HKQuantityType *type2 = [HKQuantityType quantityTypeForIdentifier:HKQuantityTypeIdentifierDistanceWalkingRunning];
HKQuantityType *type3 = [HKQuantityType quantityTypeForIdentifier:HKQuantityTypeIdentifierActiveEnergyBurned];
[healthStore requestAuthorizationToShareTypes:nil readTypes:[NSSet setWithObjects:type, type2, type3, nil] completion:^(BOOL success, NSError * _Nullable error) {
if (success) {
NSLog(@"health data request success");
}else{
NSLog(@"error %@", error);
}
}];
在 iPhone 上的 AppDelegate 中,响应此请求
-(void)applicationShouldRequestHealthAuthorization:(UIApplication *)application{
[healthStore handleAuthorizationForExtensionWithCompletion:^(BOOL success, NSError * _Nullable error) {
if (success) {
NSLog(@"phone recieved health kit request");
}
}];
}
然后执行Healthkit Delegate
:
-(void)workoutSession:(HKWorkoutSession *)workoutSession didFailWithError:(NSError *)error{
NSLog(@"session error %@", error);
}
-(void)workoutSession:(HKWorkoutSession *)workoutSession didChangeToState:(HKWorkoutSessionState)toState fromState:(HKWorkoutSessionState)fromState date:(NSDate *)date{
dispatch_async(dispatch_get_main_queue(), ^{
switch (toState) {
case HKWorkoutSessionStateRunning:
//When workout state is running, we will excute updateHeartbeat
[self updateHeartbeat:date];
NSLog(@"started workout");
break;
default:
break;
}
});
}
该写了**[self updateHeartbeat:date]**
-(void)updateHeartbeat:(NSDate *)startDate{
//first, create a predicate and set the endDate and option to nil/none
NSPredicate *Predicate = [HKQuery predicateForSamplesWithStartDate:startDate endDate:nil options:HKQueryOptionNone];
//Then we create a sample type which is HKQuantityTypeIdentifierHeartRate
HKSampleType *object = [HKSampleType quantityTypeForIdentifier:HKQuantityTypeIdentifierHeartRate];
//ok, now, create a HKAnchoredObjectQuery with all the mess that we just created.
heartQuery = [[HKAnchoredObjectQuery alloc] initWithType:object predicate:Predicate anchor:0 limit:0 resultsHandler:^(HKAnchoredObjectQuery *query, NSArray<HKSample *> *sampleObjects, NSArray<HKDeletedObject *> *deletedObjects, HKQueryAnchor *newAnchor, NSError *error) {
if (!error && sampleObjects.count > 0) {
HKQuantitySample *sample = (HKQuantitySample *)[sampleObjects objectAtIndex:0];
HKQuantity *quantity = sample.quantity;
NSLog(@"%f", [quantity doubleValueForUnit:[HKUnit unitFromString:@"count/min"]]);
}else{
NSLog(@"query %@", error);
}
}];
//wait, it's not over yet, this is the update handler
[heartQuery setUpdateHandler:^(HKAnchoredObjectQuery *query, NSArray<HKSample *> *SampleArray, NSArray<HKDeletedObject *> *deletedObjects, HKQueryAnchor *Anchor, NSError *error) {
if (!error && SampleArray.count > 0) {
HKQuantitySample *sample = (HKQuantitySample *)[SampleArray objectAtIndex:0];
HKQuantity *quantity = sample.quantity;
NSLog(@"%f", [quantity doubleValueForUnit:[HKUnit unitFromString:@"count/min"]]);
}else{
NSLog(@"query %@", error);
}
}];
//now excute query and wait for the result showing up in the log. Yeah!
[healthStore executeQuery:heartQuery];
}
您还可以开启 Healthkit 的功能。如果您有任何问题,请在下方发表评论。
我们可以直接从 Apple Watch 获取心率吗?我知道这是一个重复的问题,但在 5 个月内没有人问过这个问题。我知道您可以从健康应用程序访问它,但我不确定 "real-time" 会怎样。
无法直接访问 Apple Watch 上的任何传感器。您将不得不依赖 HealthKit 的访问权限。
苹果传道者这样说
It is not possible to create a heart monitor app at this time. The data isn't guaranteed to be sent to iPhone in real-time, so you won't be able to determine what's going on in any timely fashion.
心率原始数据信息 现已在 Watchkit for watchOS 2.0
中可用。
WatchOS 2
包括对其他现有框架的许多增强,例如 HealthKit
,允许访问实时访问心率和健康信息的健康传感器。
你可以在后面的session里查看这个信息,总共30分钟presentation.If你不想看整个session,那么你直接跳到Healthkit API
features,它在25- 28 分钟:
WatchKit for watchOS 2.0 Session in WWDC 2015
这里是源码实现link
如 HKWorkout Class Reference 中所述:
The
HKWorkout
class is a concrete subclass of theHKSample
class.HealthKit
uses workouts to track a wide range of activities. The workout object not only stores summary information about the activity (for example, duration, total distance, and total energy burned), it also acts as a container for other samples. You can associate any number of samples with a workout. In this way, you can add detailed information relevant to the workout.
在给定link的情况下,以下代码部分定义了heartRate
的采样率NSMutableArray *samples = [NSMutableArray array];
HKQuantity *heartRateForInterval =
[HKQuantity quantityWithUnit:[HKUnit unitFromString:@"count/min"]
doubleValue:95.0];
HKQuantitySample *heartRateForIntervalSample =
[HKQuantitySample quantitySampleWithType:heartRateType
quantity:heartRateForInterval
startDate:intervals[0]
endDate:intervals[1]];
[samples addObject:heartRateForIntervalSample];
正如他们所说:
You need to fine tune the exact length of your associated samples based on the type of workout and the needs of your app. Using 5 minute intervals minimizes the amount of memory needed to store the workout , while still providing a general sense of the change in intensity over the course of a long workout. Using 5 second intervals provides a much-more detailed view of the workout, but requires considerably more memory and processing.
在探索 HealthKit 和 WatchKit Extension 之后,我的发现如下:
我们不需要 WatchKit 扩展来获取心率数据。
您只需要 iPhone 与配对的 Apple Watch(这很明显)
默认的 Apple Watch 心率监测应用仅在前台运行时才立即更新 HealthKit 数据。
当默认的 Apple Watch 心率监测应用程序在后台运行时,它会以 9-10 分钟的间隔更新 HealthKit 数据。
要从 HealthKit 获取心率数据,需要定期触发以下查询。
func getSamples() { let heathStore = HKHealthStore() let heartrate = HKQuantityType.quantityType(forIdentifier: .heartRate) let sort: [NSSortDescriptor] = [ .init(key: HKSampleSortIdentifierStartDate, ascending: false) ] let sampleQuery = HKSampleQuery(sampleType: heartrate!, predicate: nil, limit: 1, sortDescriptors: sort, resultsHandler: resultsHandler) heathStore.execute(sampleQuery) } func resultsHandler(query: HKSampleQuery, results: [HKSample]?, error: Error?) { guard error == nil else { print("cant read heartRate data", error!) return } guard let sample = results?.first as? HKQuantitySample else { return } // let heartRateUnit: HKUnit = .init(from: "count/min") // let doubleValue = sample.quantity.doubleValue(for: heartRateUnit) print("heart rate is", sample) }
如果有人得到更多信息,请更新我。
快乐编码。
更新
我已将您的代码更新为清晰和通用,请注意您需要获得授权才能读取 HeathKit 数据和添加 info.plist
密钥 Privacy - Health Records Usage Description
您可以通过开始运动获取心率数据,在healthkit中查询心率数据。
请求阅读锻炼数据的权限。
HKHealthStore *healthStore = [[HKHealthStore alloc] init]; HKQuantityType *type = [HKQuantityType quantityTypeForIdentifier:HKQuantityTypeIdentifierHeartRate]; HKQuantityType *type2 = [HKQuantityType quantityTypeForIdentifier:HKQuantityTypeIdentifierDistanceWalkingRunning]; HKQuantityType *type3 = [HKQuantityType quantityTypeForIdentifier:HKQuantityTypeIdentifierActiveEnergyBurned]; [healthStore requestAuthorizationToShareTypes:nil readTypes:[NSSet setWithObjects:type, type2, type3, nil] completion:^(BOOL success, NSError * _Nullable error) { if (success) { NSLog(@"health data request success"); }else{ NSLog(@"error %@", error); } }];
在 iPhone 上的 AppDelegate 中,响应此请求
-(void)applicationShouldRequestHealthAuthorization:(UIApplication *)application{ [healthStore handleAuthorizationForExtensionWithCompletion:^(BOOL success, NSError * _Nullable error) { if (success) { NSLog(@"phone recieved health kit request"); } }]; }
然后执行
Healthkit Delegate
:-(void)workoutSession:(HKWorkoutSession *)workoutSession didFailWithError:(NSError *)error{ NSLog(@"session error %@", error); } -(void)workoutSession:(HKWorkoutSession *)workoutSession didChangeToState:(HKWorkoutSessionState)toState fromState:(HKWorkoutSessionState)fromState date:(NSDate *)date{ dispatch_async(dispatch_get_main_queue(), ^{ switch (toState) { case HKWorkoutSessionStateRunning: //When workout state is running, we will excute updateHeartbeat [self updateHeartbeat:date]; NSLog(@"started workout"); break; default: break; } }); }
该写了
**[self updateHeartbeat:date]**
-(void)updateHeartbeat:(NSDate *)startDate{ //first, create a predicate and set the endDate and option to nil/none NSPredicate *Predicate = [HKQuery predicateForSamplesWithStartDate:startDate endDate:nil options:HKQueryOptionNone]; //Then we create a sample type which is HKQuantityTypeIdentifierHeartRate HKSampleType *object = [HKSampleType quantityTypeForIdentifier:HKQuantityTypeIdentifierHeartRate]; //ok, now, create a HKAnchoredObjectQuery with all the mess that we just created. heartQuery = [[HKAnchoredObjectQuery alloc] initWithType:object predicate:Predicate anchor:0 limit:0 resultsHandler:^(HKAnchoredObjectQuery *query, NSArray<HKSample *> *sampleObjects, NSArray<HKDeletedObject *> *deletedObjects, HKQueryAnchor *newAnchor, NSError *error) { if (!error && sampleObjects.count > 0) { HKQuantitySample *sample = (HKQuantitySample *)[sampleObjects objectAtIndex:0]; HKQuantity *quantity = sample.quantity; NSLog(@"%f", [quantity doubleValueForUnit:[HKUnit unitFromString:@"count/min"]]); }else{ NSLog(@"query %@", error); } }]; //wait, it's not over yet, this is the update handler [heartQuery setUpdateHandler:^(HKAnchoredObjectQuery *query, NSArray<HKSample *> *SampleArray, NSArray<HKDeletedObject *> *deletedObjects, HKQueryAnchor *Anchor, NSError *error) { if (!error && SampleArray.count > 0) { HKQuantitySample *sample = (HKQuantitySample *)[SampleArray objectAtIndex:0]; HKQuantity *quantity = sample.quantity; NSLog(@"%f", [quantity doubleValueForUnit:[HKUnit unitFromString:@"count/min"]]); }else{ NSLog(@"query %@", error); } }]; //now excute query and wait for the result showing up in the log. Yeah! [healthStore executeQuery:heartQuery]; }
您还可以开启 Healthkit 的功能。如果您有任何问题,请在下方发表评论。