借鑒于
http://www.csdn.net/article/2015-01-23/2823686-healthkit-tutorial-with-swift/4
- 注:iOS10遇到的錯誤:
Terminating app due to uncaught exception 'NSInvalidArgumentException',
reason: 'NSHealthUpdateUsageDescription must be set in the app's Info.plist
in order to request write authorization.'
解決辦法:
我們要在info.plist文件中聲明蘋果健康的使用權(quán)限税肪,所以在info.plist中添加以下key就可以了年鸳。請求寫入和請求讀取都需要添加!
請求寫入
<key>NSHealthUpdateUsageDescription</key>
<string>some string value stating the reason</string>
請求讀取
<key>NSHealthShareUsageDescription</key>
<string>some string value stating the reason</string>
從iOS 10 因蘋果健康導(dǎo)致閃退 crash - 借鑒與簡書作者文章 找到的解決辦法,謝謝
1、第一步首先需要開啟HealthKit
HealthKit.png
2牵舱、新建一個HealthKitManage類,繼承于NSObject
- (1)首先在.h文件里面聲明一個屬性
@property (nonatomic, strong) HKHealthStore *healthStore;
- (2)導(dǎo)入頭文件
#import <HealthKit/HealthKit.h>
#import <UIKit/UIDevice.h>
#define HKVersion [[[UIDevice currentDevice] systemVersion] doubleValue]
#define CustomHealthErrorDomain @"com.sdqt.healthError"
- (3)創(chuàng)建單例方法
+(id)shareInstance
{
static id manager ;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
manager = [[[self class] alloc] init];
});
return manager;
}
- (4)檢查是否支持獲取健康數(shù)據(jù)
/*
* @brief 檢查是否支持獲取健康數(shù)據(jù)
*/
- (void)authorizeHealthKit:(void(^)(BOOL success, NSError *error))compltion
{
if(HKVersion >= 8.0)
{
if (![HKHealthStore isHealthDataAvailable]) {
NSError *error = [NSError errorWithDomain: @"com.raywenderlich.tutorials.healthkit" code: 2 userInfo: [NSDictionary dictionaryWithObject:@"HealthKit is not available in th is Device" forKey:NSLocalizedDescriptionKey]];
if (compltion != nil) {
compltion(false, error);
}
return;
}
if ([HKHealthStore isHealthDataAvailable]) {
if(self.healthStore == nil)
self.healthStore = [[HKHealthStore alloc] init];
/*
組裝需要讀寫的數(shù)據(jù)類型
*/
NSSet *writeDataTypes = [self dataTypesToWrite];
NSSet *readDataTypes = [self dataTypesRead];
/*
注冊需要讀寫的數(shù)據(jù)類型帆喇,也可以在“健康”APP中重新修改
*/
[self.healthStore requestAuthorizationToShareTypes:writeDataTypes readTypes:readDataTypes completion:^(BOOL success, NSError *error) {
if (compltion != nil) {
NSLog(@"error->%@", error.localizedDescription);
compltion (success, error);
}
}];
}
}
else {
NSDictionary *userInfo = [NSDictionary dictionaryWithObject:@"iOS 系統(tǒng)低于8.0" forKey:NSLocalizedDescriptionKey];
NSError *aError = [NSError errorWithDomain:CustomHealthErrorDomain code:0 userInfo:userInfo];
compltion(0,aError);
}
}
/*!
* @brief 寫權(quán)限
* @return 集合
*/
- (NSSet *)dataTypesToWrite
{
HKQuantityType *heightType = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierHeight];
HKQuantityType *weightType = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierBodyMass];
HKQuantityType *temperatureType = [HKQuantityType quantityTypeForIdentifier:HKQuantityTypeIdentifierBodyTemperature];
HKQuantityType *activeEnergyType = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierActiveEnergyBurned];
return [NSSet setWithObjects:heightType, temperatureType, weightType,activeEnergyType,nil];
}
/*!
* @brief 讀權(quán)限
* @return 集合
*/
- (NSSet *)dataTypesRead
{
HKQuantityType *heightType = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierHeight];
HKQuantityType *weightType = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierBodyMass];
HKQuantityType *temperatureType = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierBodyTemperature];
HKCharacteristicType *birthdayType = [HKObjectType characteristicTypeForIdentifier:HKCharacteristicTypeIdentifierDateOfBirth];
HKCharacteristicType *sexType = [HKObjectType characteristicTypeForIdentifier:HKCharacteristicTypeIdentifierBiologicalSex];
HKQuantityType *stepCountType = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierStepCount];
HKQuantityType *distance = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierDistanceWalkingRunning];
HKQuantityType *activeEnergyType = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierActiveEnergyBurned];
return [NSSet setWithObjects:heightType, temperatureType,birthdayType,sexType,weightType,stepCountType, distance, activeEnergyType,nil];
}
- (5)讀取步數(shù)
//獲取步數(shù)
- (void)getStepCount:(void(^)(double value, NSError *error))completion
{
HKQuantityType *stepType = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierStepCount];
NSSortDescriptor *timeSortDescriptor = [[NSSortDescriptor alloc] initWithKey:HKSampleSortIdentifierEndDate ascending:NO];
// Since we are interested in retrieving the user's latest sample, we sort the samples in descending order, and set the limit to 1. We are not filtering the data, and so the predicate is set to nil.
HKSampleQuery *query = [[HKSampleQuery alloc] initWithSampleType:stepType predicate:[HealthKitManage predicateForSamplesToday] limit:HKObjectQueryNoLimit sortDescriptors:@[timeSortDescriptor] resultsHandler:^(HKSampleQuery *query, NSArray *results, NSError *error) {
if(error)
{
completion(0,error);
}
else
{
NSInteger totleSteps = 0;
for(HKQuantitySample *quantitySample in results)
{
HKQuantity *quantity = quantitySample.quantity;
HKUnit *heightUnit = [HKUnit countUnit];
double usersHeight = [quantity doubleValueForUnit:heightUnit];
totleSteps += usersHeight;
}
NSLog(@"當(dāng)天行走步數(shù) = %ld",(long)totleSteps);
completion(totleSteps,error);
}
}];
[self.healthStore executeQuery:query];
}
- (6)讀取步行+跑步距離
//獲取公里數(shù)
- (void)getDistance:(void(^)(double value, NSError *error))completion
{
HKQuantityType *distanceType = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierDistanceWalkingRunning];
NSSortDescriptor *timeSortDescriptor = [[NSSortDescriptor alloc] initWithKey:HKSampleSortIdentifierEndDate ascending:NO];
HKSampleQuery *query = [[HKSampleQuery alloc] initWithSampleType:distanceType predicate:[HealthKitManage predicateForSamplesToday] limit:HKObjectQueryNoLimit sortDescriptors:@[timeSortDescriptor] resultsHandler:^(HKSampleQuery * _Nonnull query, NSArray<__kindof HKSample *> * _Nullable results, NSError * _Nullable error) {
if(error)
{
completion(0,error);
}
else
{
double totleSteps = 0;
for(HKQuantitySample *quantitySample in results)
{
HKQuantity *quantity = quantitySample.quantity;
HKUnit *distanceUnit = [HKUnit meterUnitWithMetricPrefix:HKMetricPrefixKilo];
double usersHeight = [quantity doubleValueForUnit:distanceUnit];
totleSteps += usersHeight;
}
NSLog(@"當(dāng)天行走距離 = %.2f",totleSteps);
completion(totleSteps,error);
}
}];
[self.healthStore executeQuery:query];
}
- (7)逼龟、NSPredicate當(dāng)天時間段的方法實(shí)現(xiàn)
/*!
* @brief 當(dāng)天時間段
*
* @return 時間段
*/
+ (NSPredicate *)predicateForSamplesToday {
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDate *now = [NSDate date];
NSDateComponents *components = [calendar components:NSCalendarUnitYear|NSCalendarUnitMonth|NSCalendarUnitDay fromDate:now];
[components setHour:0];
[components setMinute:0];
[components setSecond: 0];
NSDate *startDate = [calendar dateFromComponents:components];
NSDate *endDate = [calendar dateByAddingUnit:NSCalendarUnitDay value:1 toDate:startDate options:0];
NSPredicate *predicate = [HKQuery predicateForSamplesWithStartDate:startDate endDate:endDate options:HKQueryOptionNone];
return predicate;
}
3、在控制器里展示出來讀取的數(shù)據(jù)
(1)汹想、首先導(dǎo)入頭文件外邓,并添加Label
#import "HealthKitManage.h"
@interface ViewController ()
@end
@implementation ViewController
{
UILabel *stepLabel;
UILabel *distanceLabel;
}
(2)創(chuàng)建界面,展示數(shù)據(jù)
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
UIButton *btn1 = [UIButton buttonWithType:UIButtonTypeCustom];
btn1.frame = CGRectMake(50, 100, 100, 40);
[btn1 setTitle:@"計步" forState:UIControlStateNormal];
btn1.backgroundColor = [UIColor cyanColor];
[self.view addSubview:btn1];
[btn1 addTarget:self action:@selector(onClickBtn1) forControlEvents:UIControlEventTouchUpInside];
UIButton *btn2 = [UIButton buttonWithType:UIButtonTypeCustom];
btn2.frame = CGRectMake(50, 160, 100, 40);
[btn2 setTitle:@"距離" forState:UIControlStateNormal];
btn2.backgroundColor = [UIColor cyanColor];
[self.view addSubview:btn2];
[btn2 addTarget:self action:@selector(onClickBtn2) forControlEvents:UIControlEventTouchUpInside];
stepLabel = [[UILabel alloc] initWithFrame:CGRectMake(50, 220, 200, 40)];
stepLabel.backgroundColor = [UIColor cyanColor];
[self.view addSubview:stepLabel];
distanceLabel = [[UILabel alloc] initWithFrame:CGRectMake(50, 280, 200, 40)];
distanceLabel.backgroundColor = [UIColor cyanColor];
[self.view addSubview:distanceLabel];
}
- (void)onClickBtn1
{
HealthKitManage *manage = [HealthKitManage shareInstance];
[manage authorizeHealthKit:^(BOOL success, NSError *error) {
if (success) {
NSLog(@"success");
[manage getStepCount:^(double value, NSError *error) {
NSLog(@"1count-->%.0f", value);
NSLog(@"1error-->%@", error.localizedDescription);
dispatch_async(dispatch_get_main_queue(), ^{
stepLabel.text = [NSString stringWithFormat:@"步數(shù):%.0f步", value];
});
}];
}
else {
NSLog(@"fail");
}
}];
}
- (void)onClickBtn2
{
HealthKitManage *manage = [HealthKitManage shareInstance];
[manage authorizeHealthKit:^(BOOL success, NSError *error) {
if (success) {
NSLog(@"success");
[manage getDistance:^(double value, NSError *error) {
NSLog(@"2count-->%.2f", value);
NSLog(@"2error-->%@", error.localizedDescription);
dispatch_async(dispatch_get_main_queue(), ^{
distanceLabel.text = [NSString stringWithFormat:@"公里數(shù):%.2f公里", value];
});
}];
}
else {
NSLog(@"fail");
}
}];
}
4古掏、展示成果
成果展示圖.png
二损话、使用CoreMotion獲取計步信息
目前只使用到計步功能,個人感覺CoreMotion與HealthKit在計步方面的區(qū)別:HealthKit中計步信息可以通過“健康A(chǔ)pp”進(jìn)行修改。
1丧枪、info.plist中
<key>NSMotionUsageDescription</key>
<string>Privacy - Motion Usage Description</string>
2光涂、上代碼
#import <CoreMotion/CoreMotion.h>
@property (nonatomic, strong) CMPedometer *pedometer;
_pedometer = [[CMPedometer alloc] init];
if ([CMPedometer isStepCountingAvailable]) {
//獲取昨天的步數(shù)與距離數(shù)據(jù)
[_pedometer queryPedometerDataFromDate:[NSDate dateWithTimeIntervalSinceNow:-60*60*24*2] toDate:[NSDate dateWithTimeIntervalSinceNow:-60*60*24*1] withHandler:^(CMPedometerData * _Nullable pedometerData, NSError * _Nullable error) {
if (error) {
NSLog(@"error===%@",error);
}
else {
NSLog(@"步數(shù)===%@",pedometerData.numberOfSteps);
NSLog(@"距離===%@",pedometerData.distance);
}
}];
} else {
NSLog(@"不可用===");
}
借鑒兩篇文章代碼,多謝
CMPedometer(計步器)使用拧烦,獲取用戶行走步數(shù)忘闻、距離等信息
華山論劍之淺談iOS計步功能