最近在做專案的時候,突然接到產品經理給的一個需求,要求在專案中統計使用者每日步數,具體要求就是獲取手機健康應用中統計的每日步數,然後以圖形方式顯示。
剛聽到這個需求的時候就想到了蘋果在iOS8系統推出之時順帶出的HealthKit框架,不過對於其API倒是非常的陌生。於是就開始在網上查詢資料,百度,谷歌一番之後,發現也未能找到一個資料能夠很好地引導新手使用該框架(可能是我沒找到好的-_-!),經過幾天的個人摸索,也算是有點心得體會,在這裡就將自己對該框架相關的使用做個梳理,也希望能夠為接下來即將接觸和使用該框架的童鞋提供一點小小的幫助。如有什麼疑問或者不對的地方歡迎提出。以下內容以獲取步數為例,其他資料獲取可以此類推。
一、專案中關聯HealthKit框架
首先填寫好你專案的Bundle Identifier並且選好Team(這兩個東西最好事先設定好,以免之後又得重新關聯),然後在專案物理檔案結構中點選對應的專案,在TARGETS中選擇你自身的專案,再在右側選擇Capabilities選項
從中找到HealthKit這項,點選右側的開關開啟,當出現中間紅框所示的內容,表示專案與HealthKit框架關聯成功了
你會在專案中看到多了HealthKit.framework和.entitlements結尾的這兩個檔案,OK一切順利,接下來就可以Code了。
二、HealthKit所支援的系統和裝置
因為HealthKit框架是在iOS8系統出來之時一同推出的,所以該框架目前只支援iOS8及以上系統,目前支援的裝置有iPhone、iWatch,要記得iPad是不支援的哦,如果你的程式碼同時支援iPhone和iPad裝置,那麼記得判斷下裝置還有系統版本號,以免出現不必要的奔潰現象。在專案中匯入後,你也可以使用以下程式碼判斷該裝置的系統能否使用健康資料:
1 |
[HKHealthStore isHealthDataAvailable] |
三、應用授權
要想獲取健康資料中的步數,則需要通過使用者許可才行。具體可以使用以下程式碼進行授權:
1 2 3 4 5 6 7 8 9 |
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:
方法,用於對應用授權需要獲取和分享的健康資料:
1、第一個引數傳入一個
NSSet
型別資料,用於告知使用者,我的app可能會在你的健康資料庫中修改這些選項資料(顯然目前我們不需要,傳nil)
2、第二個引數也是傳入NSSet
型別資料,告知使用者,我的app可能會從你的資料庫中讀取以下幾項資料
3、第三個是授權許可回撥,BOOL值success
用於區分使用者是否允許應用向資料庫存取資料
四、獲取健康步數
授權完成之後,我們接下來就可以呼叫API來獲取資料庫資料了。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
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]; |
這段程式碼主要做了以下幾件事情:
1、第一段通過傳入一個列舉值HKQuantityTypeIdentifierStepCount來建立一個樣品類的例項,用於告知,我接下來要獲取的資料是步數>2、第二段程式碼通過建立一個NSPredicate類的例項,用於獲取在某個時間段的資料,這裡startDate和endDate傳入nil,表示獲取全部資料,第三個引數傳入一個Option,裡面有三個值,這個引數我試驗了下不同的值代入,發現返回的結果都是一樣的,要是有誰知道這個值是做什麼用的麻煩告知我一聲~
3、第三段程式碼建立了一個NSSortDescriptor類例項,用於對查詢的結果排序
4、第四段程式碼通過呼叫HKSampleQuery類的例項方法獲取所需資料
5、最後一行程式碼用於執行資料查詢操作
通過這段程式碼獲取的資料,列印出來會發現,它獲取的是比較詳盡的資料,精確到每一小段時間從開始時間到結束時間內所獲取的步數。
五、資料採集
有時候需求並不需要了解這麼詳盡的資料,只希望獲取每小時、每天或者每月的步數,那麼我們就需要用到另一個新類HKStatisticsCollectionQuery
進行資料的分段採集
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
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]; |
1、第一段程式碼所做的和之前的一樣,定義需要獲取的資料為步數
2、第二段程式碼建立一個NSDateComponents類例項,設定我要獲取的步數時間間隔,這裡設定為按天統計,這裡也可以設定按小時或者按月統計
3、第三段程式碼建立查詢統計物件collectionQuery
,通過傳入四個引數進行初始化:
1、第一個引數同上面一樣,設定需要查詢的型別
2、第二個引數傳入一個NSPredicate例項,目前這裡傳nil
3、第三個引數是關鍵,傳入一個Option可選值,告訴查詢統計物件我需要獲取的是啥,這裡傳入HKStatisticsOptionCumulativeSum | HKStatisticsOptionSeparateBySource
值,獲取時間段的步數和以及將資料根據不同的資料來源進行分段
4、第四個引數傳入一個錨點,類似於陣列的索引值,查詢將會從改錨點開始查詢,這裡可以根據不同的錨點值,獲取日/周/月/年資料
4、第四段程式碼是將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