詳解iOS 計(jì)步器的幾種實(shí)現(xiàn)方式
這篇文章介紹兩種可以獲取計(jì)步數(shù)據(jù)的方法,一種是采用CMPedometer獲取手機(jī)計(jì)步器數(shù)據(jù),另一種是采用HealthKit框架從手機(jī)健康A(chǔ)pp中獲取計(jì)步數(shù)據(jù)。另外玩了一下寫入數(shù)據(jù)到健康A(chǔ)pp。有描述不當(dāng)之處,望指點(diǎn)。
花絮(用HealthKit框架構(gòu)建app,寫入數(shù)據(jù)到蘋果健康app中,QQ和Keep等第三方app的運(yùn)動(dòng)數(shù)據(jù)都會(huì)隨之改變,猜測(cè)它們的運(yùn)動(dòng)數(shù)據(jù)是直接從蘋果健康app中獲取,而且沒有過濾掉其它數(shù)據(jù)來源。而微信運(yùn)動(dòng)的數(shù)據(jù)不會(huì)變,猜測(cè)其來源可能是使用CMPedometer類獲取的,因?yàn)闇y(cè)試發(fā)現(xiàn)把微信運(yùn)動(dòng)的數(shù)據(jù)來源(蘋果健康)關(guān)閉后,依然會(huì)有運(yùn)動(dòng)數(shù)據(jù),而且該運(yùn)動(dòng)數(shù)據(jù)和CMPedometer類獲取的一致。)
使用CMPedometer類來獲取步數(shù)和距離
使用時(shí)需要導(dǎo)入<CoreMotion/CoreMotion.h>,此類在iOS8之后才可用,在iOS8之前,使用CMStepCounter類(在iOS8之后被CMPedometer替代)來獲取步數(shù),使用方法如CMPedometer類相似。
CMPedometer
+ (BOOL)isStepCountingAvailable; 設(shè)備是否支持計(jì)步功能
+ (BOOL)isDistanceAvailable; 除了計(jì)步,設(shè)備是否支持距離估計(jì)
+ (BOOL)isFloorCountingAvailable; 除了計(jì)步,設(shè)備是否支持臺(tái)階計(jì)數(shù)
+ (BOOL)isPaceAvailable NS_AVAILABLE(NA,9_0);除了計(jì)步,設(shè)備是否支持速度估計(jì)
+(BOOL)isCadenceAvailable NS_AVAILABLE(NA,9_0);除了計(jì)步,設(shè)備是否支持節(jié)奏估計(jì)
+ (BOOL)isPedometerEventTrackingAvailable NS_AVAILABLE(NA,10_0) __WATCHOS_AVAILABLE(3_0);設(shè)備是否支持計(jì)步器事件
- (void)queryPedometerDataFromDate:(NSDate *)start toDate:(NSDate *)end withHandler:(CMPedometerHandler)handler;在給定時(shí)間范圍內(nèi)查詢用戶的行走活動(dòng),數(shù)據(jù)最多可以使用7天內(nèi)有效,返回的數(shù)據(jù)是從系統(tǒng)范圍的歷史記錄中計(jì)算出來的,該歷史記錄是在后臺(tái)連續(xù)收集的。結(jié)果返回在串行隊(duì)列中。
- (void)startPedometerUpdatesFromDate:(NSDate *)start withHandler:(CMPedometerHandler)handler;在串行隊(duì)列上啟動(dòng)一系列連續(xù)計(jì)步器更新到處理程序。 對(duì)于每次更新,應(yīng)用程序?qū)闹付ǖ拈_始日期和與最新確定相關(guān)聯(lián)的時(shí)間戳開始收到累積的行人活動(dòng)。 如果應(yīng)用程序在后臺(tái)進(jìn)行背景調(diào)整,則應(yīng)用程序?qū)⒃谙麓胃轮惺盏皆诤笈_(tái)期間累積的所有行人活動(dòng)。
-(void)stopPedometerUpdates;停止計(jì)步器更新
-(void)startPedometerEventUpdatesWithHandler:(CMPedometerEventHandler)handler NS_AVAILABLE(NA,10_0) __WATCHOS_AVAILABLE(3_0);在串行隊(duì)列上啟動(dòng)計(jì)步器事件更新。 事件僅在應(yīng)用程序在前臺(tái)/后臺(tái)運(yùn)行時(shí)可用。
-(void)stopPedometerEventUpdates NS_AVAILABLE(NA,10_0) __WATCHOS_AVAILABLE(3_0);停止計(jì)步器事件更新
CMPedometerData
@property(readonly, nonatomic) NSDate *startDate;計(jì)步器數(shù)據(jù)有效期間的開始時(shí)間。這是會(huì)話或歷史查詢請(qǐng)求的開始時(shí)間。
@property(readonly, nonatomic) NSDate *endDate;計(jì)步器數(shù)據(jù)有效期間的結(jié)束時(shí)間。對(duì)于更新,這是最新更新的時(shí)間。 對(duì)于歷史查詢,這是請(qǐng)求的結(jié)束時(shí)間。
@property(readonly, nonatomic) NSNumber *numberOfSteps;用戶的步數(shù)
@property(readonly, nonatomic, nullable) NSNumber *distance; 用戶行走和跑步時(shí)估計(jì)的一米為單位的距離。若設(shè)備不支持則值為nil
@property(readonly, nonatomic, nullable) NSNumber *floorsAscended;上樓的大概樓層數(shù),若設(shè)備不支持則值為nil
@property(readonly, nonatomic, nullable) NSNumber *floorsDescended;下樓的大概樓層數(shù), 若設(shè)備不支持則值為nil
@property(readonly, nonatomic, nullable) NSNumber *currentPace NS_AVAILABLE(NA,9_0);對(duì)于更新,這將以s / m(每米秒)返回當(dāng)前速度。 如果滿足以下條件,則值為零:1. 資料尚未公布 2. 歷史查詢 3.平臺(tái)不支持
@property(readonly, nonatomic, nullable) NSNumber *currentCadence NS_AVAILABLE(NA,9_0);對(duì)于更新,這將返回以秒為單位執(zhí)行行走的節(jié)奏。 如果滿足以下條件,則值為零:1. 資料尚未公布 2. 歷史查詢 3.平臺(tái)不支持
@property(readonly, nonatomic, nullable) NSNumber *averageActivePace NS_AVAILABLE(NA,10_0);對(duì)于更新,這將返回自startPedometerUpdatesFromDate:withHandler :,以s / m(每米秒))的平均活動(dòng)速度。 對(duì)于歷史查詢,這將返回startDate和endDate之間的平均活動(dòng)速度。 平均主動(dòng)速度省略了非活動(dòng)時(shí)間,平均步調(diào)從用戶移動(dòng)。 如果滿足以下條件,則值為零:1. 對(duì)于歷史信息查詢,信息無效。例如用戶在開始時(shí)間和結(jié)束時(shí)間內(nèi)沒有移動(dòng) 2. 平臺(tái)不支持
CMPedometerEvent
@property(readonly, nonatomic) NSDate *date;事件發(fā)生的時(shí)間
@property(readonly, nonatomic) CMPedometerEventType type;描述行走活動(dòng)過渡的事件類型
typedef void (^CMPedometerHandler)(CMPedometerData * __nullable pedometerData, NSError * __nullable error) __TVOS_PROHIBITED;當(dāng)計(jì)步器數(shù)據(jù)可用時(shí)要調(diào)用的block的類型
typedef void (^CMPedometerEventHandler)(CMPedometerEvent * __nullable pedometerEvent, NSError * __nullable error) NS_AVAILABLE(NA, 10_0) __WATCHOS_AVAILABLE(3_0) __TVOS_PROHIBITED;//當(dāng)計(jì)步器事件可用時(shí)將被調(diào)用的block的類型。
獲取步數(shù)和距離的方法
1、使用<CoreMotion/CoreMotion.h>庫需要在info.plist文件中增加NSMotionUsageDescription鍵。
2、可以使用isStepCountingAvailable或者isDistanceAvailable來檢查設(shè)備是否支持計(jì)步功能或距離功能。
3、創(chuàng)建CMPedometer實(shí)例對(duì)象
/// 創(chuàng)建計(jì)步器對(duì)象 if ([CMPedometer isStepCountingAvailable]) { // 8.0 之后可使用 self.pedometer = [[CMPedometer alloc] init]; }
4、調(diào)用- (void)startPedometerUpdatesFromDate:(NSDate *)start withHandler:(CMPedometerHandler)handler方法獲取從某個(gè)時(shí)間點(diǎn)到現(xiàn)在的步數(shù),距離,樓層等信息。此方法會(huì)實(shí)時(shí)更新數(shù)據(jù)。
[self.pedometer startPedometerUpdatesFromDate:fromDate withHandler:^(CMPedometerData * _Nullable pedometerData, NSError * _Nullable error) { // 如果沒有錯(cuò)誤,具體信息從pedometerData參數(shù)中獲取 }];
5、不需要使用的時(shí)候,調(diào)用stopPedometerUpdates方法停止更新
[self.pedometer stopPedometerUpdates];
6、如果不需要實(shí)時(shí)更新數(shù)據(jù),可直接調(diào)用- (void)queryPedometerDataFromDate:(NSDate *)start toDate:(NSDate *)end withHandler:(CMPedometerHandler)handler;查詢某個(gè)時(shí)間段內(nèi)的數(shù)據(jù),不過只能查詢七天內(nèi)的數(shù)據(jù)。
[self.pedometer queryPedometerDataFromDate:start toDate:end withHandler:^(CMPedometerData * _Nullable pedometerData, NSError * _Nullable error) { // 如果沒有錯(cuò)誤,具體信息從pedometerData參數(shù)中獲取 }];
使用HealthKit框架獲取蘋果健康數(shù)據(jù)
在HealthKit中,使用HKHealthStore類來訪問健康數(shù)據(jù),健康數(shù)據(jù)的類型有很多類,蘋果健康app中的健身記錄、營養(yǎng)攝入、睡眠狀況等等都可以進(jìn)行數(shù)據(jù)讀取和共享(即第三方app寫入數(shù)據(jù)到蘋果健康app)。
大概步驟:
1、在Xcode中, 打開HealthKit 功能
開啟HealthKit功能
1、調(diào)用isHealthDataAvailable方法檢查設(shè)備HealthKit是否可用。
if ([HKHealthStore isHealthDataAvailable]) { // add code to use HealthKit here... }
2、如果可用,創(chuàng)建HKHealthStore對(duì)象
self.healthStore = [[HKHealthStore alloc] init];
3、向用戶請(qǐng)求授權(quán)共享或讀取健康數(shù)據(jù), 調(diào)用- (void)requestAuthorizationToShareTypes:(nullable NSSet<HKSampleType *> *)typesToShare readTypes:(nullable NSSet<HKObjectType *> *)typesToRead completion:(void (^)(BOOL success, NSError * _Nullable error))completion;方法,例如下面請(qǐng)求讀取步數(shù)和距離數(shù)據(jù)
NSSet<HKSampleType *> *shareTypes = nil; HKQuantityType *stepType = [HKQuantityType quantityTypeForIdentifier:(HKQuantityTypeIdentifierStepCount)]; HKQuantityType *distanceType = [HKQuantityType quantityTypeForIdentifier:HKQuantityTypeIdentifierDistanceWalkingRunning]; NSSet<HKObjectType *> *readTypes = [NSSet setWithObjects:stepType, distanceType, nil]; [self.healthStore requestAuthorizationToShareTypes:shareTypes readTypes:readTypes completion:^(BOOL success, NSError * _Nullable error) { }];
4、在info.plist文件中,增加NSHealthShareUsageDescription用于讀取數(shù)據(jù)的描述和NSHealthUpdateUsageDescription用于寫入數(shù)據(jù)的描述
5、用戶授權(quán)之后,就可以對(duì)健康數(shù)據(jù)中授權(quán)的項(xiàng)目進(jìn)行讀取或?qū)懭氩僮?。下面的代碼是查詢一段歷史的計(jì)步記錄的示例,如CMPedemoter不同的是查詢到的數(shù)據(jù)不是實(shí)時(shí)更新的。
// 查詢數(shù)據(jù)的類型,比如計(jì)步,行走+跑步距離等等 HKQuantityType *quantityType = [HKQuantityType quantityTypeForIdentifier:(HKQuantityTypeIdentifierStepCount)]; // 謂詞,用于限制查詢返回結(jié)果 NSPredicate *predicate = [HKQuery predicateForSamplesWithStartDate:start endDate:end options:(HKQueryOptionNone)]; NSCalendar *calendar = [NSCalendar currentCalendar]; NSDateComponents *anchorComponents = [calendar components:NSCalendarUnitYear|NSCalendarUnitMonth|NSCalendarUnitDay fromDate:[NSDate date]]; // 用于錨集合的時(shí)間間隔 NSDate *anchorDate = [calendar dateFromComponents:anchorComponents]; // 采樣時(shí)間間隔 NSDateComponents *intervalComponents = [[NSDateComponents alloc] init]; intervalComponents.day = 1; // 創(chuàng)建統(tǒng)計(jì)查詢對(duì)象 HKStatisticsCollectionQuery *query = [[HKStatisticsCollectionQuery alloc] initWithQuantityType:quantityType quantitySamplePredicate:predicate options:(HKStatisticsOptionCumulativeSum|HKStatisticsOptionSeparateBySource) anchorDate:anchorDate intervalComponents:intervalComponents]; query.initialResultsHandler = ^(HKStatisticsCollectionQuery * _Nonnull query, HKStatisticsCollection * _Nullable result, NSError * _Nullable error) { NSMutableArray *resultArr = [NSMutableArray array]; if (error) { NSLog(@"error: %@", error); } else { for (HKStatistics *statistics in [result statistics]) { NSLog(@"statics: %@,\n sources: %@", statistics, statistics.sources); for (HKSource *source in statistics.sources) { // 過濾掉其它應(yīng)用寫入的健康數(shù)據(jù) if ([source.name isEqualToString:[UIDevice currentDevice].name]) { // 獲取到步數(shù) double step = round([[statistics sumQuantityForSource:source] doubleValueForUnit:[HKUnit countUnit]]); } } } } // 執(zhí)行查詢請(qǐng)求 [self.healthStore executeQuery:query];
如果要寫入數(shù)據(jù)到蘋果HealtkKit中,過程類似,下面的示例是寫入步數(shù)到健康數(shù)據(jù)。(QQ中運(yùn)動(dòng)的步數(shù)和Keep中的步數(shù)都是從健康數(shù)據(jù)中獲取的步數(shù),而且沒有過濾其它應(yīng)用寫入的數(shù)據(jù),所以想要修改QQ或Keep中的步數(shù),可以用自己的app寫入步數(shù)數(shù)據(jù),親測(cè)有效)
①請(qǐng)求用戶授權(quán)
HKQuantityType *stepType = [HKQuantityType quantityTypeForIdentifier:HKQuantityTypeIdentifierStepCount]; NSSet *shareTypes = [NSSet setWithObjects:stepType, nil]; [self.healthStore requestAuthorizationToShareTypes:shareTypes readTypes:nil completion:^(BOOL success, NSError * _Nullable error) { }];
②寫入數(shù)據(jù)
double step = [self.textField.text doubleValue]; HKQuantityType *stepType = [HKQuantityType quantityTypeForIdentifier:HKQuantityTypeIdentifierStepCount]; HKQuantity *stepQuantity = [HKQuantity quantityWithUnit:[HKUnit countUnit] doubleValue:step]; HKQuantitySample *stepSample = [HKQuantitySample quantitySampleWithType:stepType quantity:stepQuantity startDate:[self getTodayStartDate] endDate:[NSDate date]]; [self.healthStore saveObject:stepSample withCompletion:^(BOOL success, NSError * _Nullable error) { if (error) { NSLog(@"error: %@", error.localizedDescription); } dispatch_async(dispatch_get_main_queue(), ^{ self.stateLabel.text = success ? @"成功" : @"失敗"; }); }];
項(xiàng)目中使用了HealthKit時(shí),上架需要注意點(diǎn):
- Your app may not use information gained through the use of the HealthKit framework for advertising or similar services. Note that you may still serve advertising in an app that uses the HealthKit framework, but you cannot use data from the HealthKit store to serve ads.//你的應(yīng)用不應(yīng)該將HealthKit收集的數(shù)據(jù)用于廣告或類似的服務(wù)。注意,可能在使用HealthKit框架應(yīng)用中還是要服務(wù)廣告,但是你不能使用HealthKit中的數(shù)據(jù)來服務(wù)廣告。
- You must not disclose any information gained through HealthKit to a third party without express permission from the user. Even with permission, you can only share information to a third party if they are also providing a health or fitness service to the user.// 在沒有用戶的明確允許下,你不能向第三方展示任何HealthKit收集的數(shù)據(jù)。即使用戶允許,你也只能向提供健康或健身服務(wù)的第三方展示這些數(shù)據(jù)
- You cannot sell information gained through HealthKit to advertising platforms, data brokers, or information resellers.// 你不能將HealthKit收集的數(shù)據(jù)出售給廣告平臺(tái)、數(shù)據(jù)代理人或者信息經(jīng)銷商
- If the user consents, you may share his or her HealthKit data with a third party for medical research.// 如果用戶允許,你可以將HealthKit數(shù)據(jù)共享給第三方用于醫(yī)學(xué)研究。
- You must clearly disclose to the user how you and your app will use their HealthKit data.//你必須明確說明,你和你的應(yīng)用會(huì)怎樣使用用戶的HealthKit數(shù)據(jù)。
You must also provide a privacy policy for any app that uses the HealthKit framework. You can find guidance on creating a privacy policy at the following sites://你必須為每個(gè)使用HealthKit框架的應(yīng)用提供一份隱私策略。你可以在以下網(wǎng)站找到創(chuàng)建隱私策略的指導(dǎo):
1、Personal Health Record model (for non-HIPAA apps): http://www.healthit.gov/policy-researchers-implementers/personal-health-record-phr-model-privacy-notice
2、HIPAA model (for HIPAA covered apps): http://www.hhs.gov/ocr/privacy/hipaa/modelnotices.html
參考文章
https://developer.apple.com/documentation/healthkit#classes
以上就是本文的全部內(nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
iOS開發(fā)中使用UIScrollView實(shí)現(xiàn)圖片輪播和點(diǎn)擊加載
這篇文章主要介紹了iOS開發(fā)中使用UIScrollView實(shí)現(xiàn)圖片輪播和點(diǎn)擊加載的方法,代碼基于傳統(tǒng)的Objective-C,需要的朋友可以參考下2015-12-12iOS實(shí)現(xiàn)scrollview上拉顯示Navbar下拉隱藏功能詳解
這篇文章主要給大家介紹了利用iOS實(shí)現(xiàn)scrollview上拉顯示Navbar下拉隱藏功能的相關(guān)資料,文中介紹的非常詳細(xì),對(duì)大家具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起看看吧。2017-05-05詳解iOS應(yīng)用開發(fā)中Core Data數(shù)據(jù)存儲(chǔ)的使用
這篇文章主要介紹了iOS應(yīng)用開發(fā)中Core Data數(shù)據(jù)存儲(chǔ)的使用,Core Data可以看作是一個(gè)內(nèi)嵌型數(shù)據(jù)庫SQLite的iOS專用版本,需要的朋友可以參考下2016-02-02iOS毛玻璃效果的實(shí)現(xiàn)及圖片模糊效果的三種方法
App設(shè)計(jì)時(shí)往往會(huì)用到一些模糊效果或者毛玻璃效果,iOS目前已提供一些模糊API可以讓我們方便是使用,本文給大家介紹iOS毛玻璃效果的實(shí)現(xiàn)及圖片模糊效果的三種方法,感興趣的朋友一起學(xué)習(xí)吧2016-01-01iOS開發(fā)之手勢(shì)識(shí)別實(shí)例
本篇文章主要介紹了iOS開發(fā)之手勢(shì)識(shí)別實(shí)例,具有一定的參考價(jià)值,有需要的可以了解一下。2016-11-11