HealthKitに保存された情報を、バックグラウンドで取れるのか検証

HealtKit(歩数や心拍数などのデータ)の分析ツールを作る場合など、バックグラウンドでデータの検証などを行いたい場合があります。
しかしAppleのHealthKitのドキュメントなどを見ていると、Healthkitのデータはバックグラウンドでは取れるけど、ロック中は取れないという記載があったため、実際に検証してみました。

#### 検証
background fetchではいつ呼ばれるのか不定のため、テスト用にバックグラウンドでの位置情報アップデート時に、Healthkitの情報取得を行うようにしてみた。

```objc:位置情報取得開始
- (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];
}
```
```objc:位置情報取得時に、HealthKitデータ(歩数)取得
- (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簡易リファレンス](http://dev.classmethod.jp/references/ios-8-healthkit-app-1/)
[[iOS][Obj-C] 今こそ HealthKit を使ってみる](http://dev.classmethod.jp/smartphone/healthkit_before_ios9/)
[HealthKit data inaccessible in background](http://stackoverflow.com/questions/30361033/healthkit-data-inaccessible-in-background)