HealtKit(歩数や心拍数などのデータ)の分析ツールを作る場合など、バックグラウンドでデータの検証などを行いたい場合があります。
しかしAppleのHealthKitのドキュメントなどを見ていると、Healthkitのデータはバックグラウンドでは取れるけど、ロック中は取れないという記載があったため、実際に検証してみました。
検証
background fetchではいつ呼ばれるのか不定のため、テスト用にバックグラウンドでの位置情報アップデート時に、Healthkitの情報取得を行うようにしてみた。
- (void)startGetLocation {
NSString* timeText = [[NSDate date] description];
[self.logText appendString:timeText];
[self.logText appendString:@" startGetLocation"];
[self.logText appendString:@"\r\n"];
_locationManager = [CLLocationManager new];
_locationManager.delegate = self;
// バックグラウンドでの更新を許可する
_locationManager.allowsBackgroundLocationUpdates = true;
// 更新を自動停止する
_locationManager.pausesLocationUpdatesAutomatically = false;
// 精度を設定する(最高制度)
_locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation;
// 位置情報の更新間隔(0m)
_locationManager.distanceFilter = kCLDistanceFilterNone;
// 位置情報の更新頻度(その他)
_locationManager.activityType = CLActivityTypeFitness;
if ([_locationManager respondsToSelector:@selector(requestAlwaysAuthorization)]) {
[_locationManager requestAlwaysAuthorization];
}
// 位置情報取得開始
[_locationManager startUpdatingLocation];
}
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations
{
NSString* timeText = [[NSDate date] description];
[self.logText appendString:timeText];
[self.logText appendString:@" didUpdateLocations"];
[self.logText appendString:@"\r\n"];
[self getHealthKitString];
}
- (void)getHealthKitString
{
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDateComponents *interval = [[NSDateComponents alloc] init];
interval.day = 1;
NSDateComponents *anchorComponents = [calendar components:NSCalendarUnitDay | NSCalendarUnitMonth | NSCalendarUnitYear
fromDate:[NSDate date]];
anchorComponents.hour = 0;
NSDate *anchorDate = [calendar dateFromComponents:anchorComponents];
HKQuantityType *quantityType = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierStepCount];
HKStatisticsCollectionQuery *query = [[HKStatisticsCollectionQuery alloc] initWithQuantityType:quantityType
quantitySamplePredicate:nil
options:HKStatisticsOptionCumulativeSum
anchorDate:anchorDate
intervalComponents:interval];
query.initialResultsHandler = ^(HKStatisticsCollectionQuery *query, HKStatisticsCollection *results, NSError *error) {
if (error) {
[self.logText appendString:[error description]];
[self.logText appendString:@"\r\n"];
return;
}
NSDate *endDate = [NSDate date];
NSDate *startDate = [calendar dateByAddingUnit:NSCalendarUnitDay
value:0
toDate:endDate
options:0];
[results enumerateStatisticsFromDate:startDate toDate:endDate
withBlock:^(HKStatistics *result, BOOL *stop) {
HKQuantity *quantity = result.sumQuantity;
[self.logText appendString:@" "];
if (quantity) {
double value = [quantity doubleValueForUnit:[HKUnit countUnit]];
NSLog(@"%f", value);
[self.logText appendString:[NSString stringWithFormat:@"%f",value]];
}
else {
[self.logText appendString:@"no data"];
}
[self.logText appendString:@"\r\n"];
}];
};
[_healthStore executeQuery:query];
}
結果
結果としては、iPhoneがロックされていない場合は正常取得できておりましたが、ロック状態になるとquery.initialResultsHandlerにて、エラーが返却されました。
Error Domain=com.apple.healthkit Code=6
"Protected health data is inaccessible"
iPhone紛失時などのセキュリティを考慮してのことだろうと思いますが、ちゃんとしてますね。Androidはどうなんだろうと気になります。
参考
[iOS 8] HealthKitを実装する(1) HealthKit簡易リファレンス
[iOS][Obj-C] 今こそ HealthKit を使ってみる
HealthKit data inaccessible in background