本文是投稿文章,作者:Mars飄殇
最近在做項目的時候,突然接到產品經理給的一個需求,要求在項目中統計用戶每日步數,具體要求就是獲取手機健康應用中統計的每日步數,然後以圖形方式顯示。
剛聽到這個需求的時候就想到了蘋果在iOS 8系統推出之時順帶出的HealthKit框架,不過對於其API倒是非常的陌生。於是就開始在網上查找資料,百度,谷歌一番之後,發現也未能找到一個資料能夠很好地引導新手使用該框架(可能是我沒找到好的-_-!),經過幾天的個人摸索,也算是有點心得體會,在這裡就將自己對該框架相關的使用做個梳理,也希望能夠為接下來即將接觸和使用該框架的童鞋提供一點小小的幫助。如有什麼疑問或者不對的地方歡迎提出。以下內容以獲取步數為例,其他數據獲取可以此類推。
一、項目中關聯HealthKit框架
HealthKit關聯路徑
首先填寫好你項目的Bundle Identifier並且選好Team(這兩個東西最好事先設置好,以免之後又得重新關聯),然後在項目物理文件結構中點選對應的項目,在TARGETS中選擇你自身的項目,再在右側選擇Capabilities選項。
HealthKit
從中找到HealthKit這項,點擊右側的開關開啟,當出現中間紅框所示的內容,表示項目與HealthKit框架關聯成功了
成功關聯HealthKit
你會在項目中看到多了HealthKit.framework和.entitlements結尾的這兩個文件,OK一切順利,接下來就可以Code了。
二、HealthKit所支持的系統和設備
因為HealthKit框架是在iOS8系統出來之時一同推出的,所以該框架目前只支持iOS8及以上系統,目前支持的設備有iPhone、iWatch,要記得iPad是不支持的哦,如果你的代碼同時支持iPhone和iPad設備,那麼記得判斷下設備還有系統版本號,以免出現不必要的奔潰現象。在項目中導入
[HKHealthStore isHealthDataAvailable]
三、應用授權
要想獲取健康數據中的步數,則需要通過用戶許可才行。具體可以使用以下代碼進行授權:
HKHealthStore *healthStore = [[HKHealthStore alloc] init]; NSSet *readObjectTypes = [NSSet setWithObjects:[HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierStepCount], nil]; [healthStore requestAuthorizationToShareTypes:nil readTypes:readObjectTypes completion:^(BOOL success, NSError *error) { if (success == YES) { //授權成功 } else { //授權失敗 } }];
這裡調用了requestAuthorizationToShareTypes: readTypes: completion:方法,用於對應用授權需要獲取和分享的健康數據:
第一個參數傳入一個NSSet類型數據,用於告知用戶,我的app可能會在你的健康數據庫中修改這些選項數據(顯然目前我們不需要,傳nil)。
第二個參數也是傳入NSSet類型數據,告知用戶,我的app可能會從你的數據庫中讀取以下幾項數據。
第三個是授權許可回調,BOOL值success用於區分用戶是否允許應用向數據庫存取數據。
四、獲取健康步數
授權完成之後,我們接下來就可以調用API來獲取數據庫數據了。
HKSampleType *sampleType = [HKSampleType quantityTypeForIdentifier:HKQuantityTypeIdentifierStepCount]; NSPredicate *predicate = [HKQuery predicateForSamplesWithStartDate:nil endDate:nil options:HKQueryOptionStrictStartDate]; NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:HKSampleSortIdentifierStartDate ascending:YES]; HKSampleQuery *sampleQuery = [[HKSampleQuery alloc] initWithSampleType:sampleType predicate:predicate limit:HKObjectQueryNoLimit sortDescriptors:@[sortDescriptor] resultsHandler:^(HKSampleQuery *query, NSArray *results, NSError *error) { if(!error && results) { for(HKQuantitySample *samples in results) { NSLog(@"%@ 至 %@ : %@", samples.startDate, samples.endDate, samples.quantity); } } else { //error } }]; [healthStore executeQuery:sampleQuery];
這段代碼主要做了以下幾件事情:
第一段通過傳入一個枚舉值HKQuantityTypeIdentifierStepCount來創建一個樣品類的實例,用於告知,我接下來要獲取的數據是步數。
第二段代碼通過創建一個NSPredicate類的實例,用於獲取在某個時間段的數據,這裡startDate和endDate傳入nil,表示獲取全部數據,第三個參數傳入一個Option,裡面有三個值,這個參數我試驗了下不同的值代入,發現返回的結果都是一樣的,要是有誰知道這個值是做什麼用的麻煩告知我一聲~
第三段代碼創建了一個NSSortDescriptor類實例,用於對查詢的結果排序。
第四段代碼通過調用HKSampleQuery類的實例方法獲取所需數據
最後一行代碼用於執行數據查詢操作
通過這段代碼獲取的數據,打印出來會發現,它獲取的是比較詳盡的數據,精確到每一小段時間從開始時間到結束時間內所獲取的步數。
五、數據采集
有時候需求並不需要了解這麼詳盡的數據,只希望獲取每小時、每天或者每月的步數,那麼我們就需要用到另一個新類HKStatisticsCollectionQuery進行數據的分段采集
HKQuantityType *quantityType = [HKQuantityType quantityTypeForIdentifier:HKQuantityTypeIdentifierStepCount]; NSDateComponents *dateComponents = [[NSDateComponents alloc] init]; dateComponents.day = 1; HKStatisticsCollectionQuery *collectionQuery = [[HKStatisticsCollectionQuery alloc] initWithQuantityType:quantityType quantitySamplePredicate:nil options: HKStatisticsOptionCumulativeSum | HKStatisticsOptionSeparateBySource anchorDate:[NSDate dateWithTimeIntervalSince1970:0] intervalComponents:dateComponents]; collectionQuery.initialResultsHandler = ^(HKStatisticsCollectionQuery *query, HKStatisticsCollection * __nullable result, NSError * __nullable error) { for (HKStatistics *statistic in result.statistics) { NSLog(@"\n%@ 至 %@", statistic.startDate, statistic.endDate); for (HKSource *source in statistic.sources) { if ([source.name isEqualToString:[UIDevice currentDevice].name]) { NSLog(@"%@ -- %f",source, [[statistic sumQuantityForSource:source] doubleValueForUnit:[HKUnit countUnit]]); } } } }; [healthStore executeQuery:collectionQuery];
第一段代碼所做的和之前的一樣,定義需要獲取的數據為步數。
第二段代碼創建一個NSDateComponents類實例,設置我要獲取的步數時間間隔,這裡設置為按天統計,這裡也可以設置按小時或者按月統計
第三段代碼創建查詢統計對象collectionQuery,通過傳入四個參數進行初始化:
a.第一個參數同上面一樣,設置需要查詢的類型
b.第二個參數傳入一個NSPredicate實例,目前這裡傳nil
c.第三個參數是關鍵,傳入一個Option可選值,告訴查詢統計對象我需要獲取的是啥,這裡傳入HKStatisticsOptionCumulativeSum | HKStatisticsOptionSeparateBySource值,獲取時間段的步數和以及將數據根據不同的數據來源進行分段
d.第四個參數傳入一個錨點,類似於數組的索引值,查詢將會從改錨點開始查詢,這裡可以根據不同的錨點值,獲取日/周/月/年數據
第四段代碼是將collectionQuery對象的block屬性initialResultsHandler進行賦值,該block會在數據查詢成功之後進行回調,從中可以獲得我們想要的數據5、最後一行執行該查詢統計操作執行這段代碼,通過打印的日志可以看到當前設備中存儲的按日間隔存儲的步行數總和了。
返回的數據中HKSource對象中的name可用於區分健康數據來源,一般只獲取設備中的步數,過濾其他第三方數據來源,目前微信、QQ所用的記步就是區分了不同的數據來源,防止作弊!!!
最後附上一個仿健康應用步數的Demo:gitHub地址:https://github.com/MarsCWD/HealthKitDemo
參考鏈接:
http://vit0.com/blog/2014/10/30/ios-8-healthkit-jie-shao/
https://segmentfault.com/a/1190000003779081