2016-04-11 13 views
13

Robię szybką aplikację na iOS, która integruje się z liczbą kroków użytkownika zgłaszaną przez aplikację Zdrowie. Mogę łatwo znaleźć liczbę kroków użytkownika w ciągu ostatniej godziny, stosując to jako moją orzecznika:HealthKit Swift robi dzisiejsze kroki

let anHourBeforeNow: NSDate = NSDate().dateByAddingTimeInterval(-60 * 60) 
let predicate = HKQuery.predicateForSamplesWithStartDate(anHourBeforeNow, endDate: NSDate(), options: .None) 

I mam resztę w dół, więc mogę z powodzeniem dostępu liczbę kroków użytkownika przez ostatnią godzinę. Ale w jaki sposób mogę uzyskać dostęp do danych kroku użytkownika od początku dnia, na przykład w aplikacji Zdrowie wyświetlanej w sekcji kroków?

Staram się zrobić coś takiego:

let date = NSDate() 
let cal = NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian)! 
let newDate = cal.startOfDayForDate(date) 
let predicate = HKQuery.predicateForSamplesWithStartDate(newDate, endDate: NSDate(), options: .None) 

ale ten kod nie dostosować do strefy czasowej (tak to daje mi początek dnia w UTC, a nie początek dnia, w którym użytkownik jest) i ja też dostaję wysoce zawyżone liczby kroków (z nieznanych powodów).

Więc jak mogę liczyć krok użytkownika do bieżącego dnia, o tej samej liczbie kroków jak podano w zdrowie, tak jak na zdjęciu:enter image description here

+0

to może pomóc zobaczyć szybką odpowiedź http://stackoverflow.com/questions/29582462/get-total-step-count-for-every-date -in-healthkit –

+0

Powinieneś podać kod zapytania i sposób obliczania liczby kroków, abyśmy mogli Ci pomóc w rozwiązaniu tego problemu. Możesz również śledzić moje odpowiedzi na http://stackoverflow.com/questions/36560367/health-handles-multiple-step-sources-differently-than-healthkit-swift po wskazówki, jeśli okaże się, że popełniasz ten sam błąd. – Allan

+0

Co NSTimeZone.localTimeZone() zwraca w swojej aplikacji? – Allan

Odpowiedz

15

Oto właściwy sposób używając HKStatisticsCollectionQuery uprzejmości kierunku od powyższego kodu.

To jest napisane w Swift 3, więc być może będziesz musiał przekonwertować kod z powrotem na 2.3 lub 2, jeśli nie na 3 jeszcze.

Swift 3

func retrieveStepCount(completion: (stepRetrieved: Double) -> Void) { 

     // Define the Step Quantity Type 
     let stepsCount = HKQuantityType.quantityType(forIdentifier: HKQuantityTypeIdentifier.stepCount) 

     // Get the start of the day   
     let date = Date() 
     let cal = Calendar(identifier: Calendar.Identifier.gregorian) 
     let newDate = cal.startOfDay(for: date) 

     // Set the Predicates & Interval 
     let predicate = HKQuery.predicateForSamples(withStart: newDate, end: Date(), options: .strictStartDate) 
     var interval = DateComponents() 
     interval.day = 1 

     // Perform the Query 
     let query = HKStatisticsCollectionQuery(quantityType: stepsCount!, quantitySamplePredicate: predicate, options: [.cumulativeSum], anchorDate: newDate as Date, intervalComponents:interval) 

     query.initialResultsHandler = { query, results, error in 

      if error != nil { 

       // Something went Wrong 
       return 
      } 

      if let myResults = results{ 
       myResults.enumerateStatistics(from: self.yesterday, to: self.today) { 
        statistics, stop in 

        if let quantity = statistics.sumQuantity() { 

         let steps = quantity.doubleValue(for: HKUnit.count()) 

         print("Steps = \(steps)") 
         completion(stepRetrieved: steps) 

        } 
       } 
      } 


     } 

     storage.execute(query) 
    } 

Objective-C

HKQuantityType *type = [HKSampleType quantityTypeForIdentifier:HKQuantityTypeIdentifierStepCount]; 

NSDate *today = [NSDate date]; 
NSDate *startOfDay = [[NSCalendar calendarWithIdentifier:NSCalendarIdentifierGregorian] startOfDayForDate:today]; 

NSPredicate *predicate = [HKQuery predicateForSamplesWithStartDate:startOfDay endDate:today options:HKQueryOptionStrictStartDate]; 
NSDateComponents *interval = [[NSDateComponents alloc] init]; 
interval.day = 1; 

HKStatisticsCollectionQuery *query = [[HKStatisticsCollectionQuery alloc] initWithQuantityType:type quantitySamplePredicate:predicate options:HKStatisticsOptionCumulativeSum anchorDate:startOfDay intervalComponents:interval]; 

query.initialResultsHandler = ^(HKStatisticsCollectionQuery * _Nonnull query, HKStatisticsCollection * _Nullable result, NSError * _Nullable error) { 
    if (error != nil) { 
    // TODO 
    } else { 
    [result enumerateStatisticsFromDate:startOfDay toDate:today withBlock:^(HKStatistics * _Nonnull result, BOOL * _Nonnull stop) { 
     HKQuantity *quantity = [result sumQuantity]; 
     double steps = [quantity doubleValueForUnit:[HKUnit countUnit]]; 
     NSLog(@"Steps : %f", steps); 
    }]; 
    } 
}; 

[self.storage executeQuery:query]; 
+0

@Gugulethu możesz wskazać, w jaki sposób mogę skasować ręcznie dodane kroki? – Byte

+0

@Byte Po prostu próbujesz zrozumieć swoje pytania - Chcesz skrócić kroki dodane ręcznie z innego źródła oprócz HealthKit? – Gugulethu

+0

NIE, chcę uzyskać wszystkie kroki wykryte przez iphone i automatycznie dodane przez inne moduły śledzenia. Ale nie chcę tych kroków, które użytkownicy dodali ręcznie do aplikacji zdrowia. – Byte

4

Zapytanie uzywasz bierze wszystko z użytkownika rejestrowane kroki z Healthkit, a nie inteligentne filtrowanie duplikatów wykonanych w aplikacji Health. Zamiast tego chcesz uzyskać dane zagregowanego kroku, które aplikacja Health generuje po połączeniu kroków z różnych źródeł, aby uzyskać dokładną wartość.

Aby to zrobić, można użyć tego kodu:

func recentSteps2(completion: (Double, NSError?) ->()) 
{ // this function gives you all of the steps the user has taken since the beginning of the current day. 

    checkAuthorization() // checkAuthorization just makes sure user is allowing us to access their health data. 
    let type = HKSampleType.quantityTypeForIdentifier(HKQuantityTypeIdentifierStepCount) // The type of data we are requesting 


    let date = NSDate() 
    let cal = NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian)! 
    let newDate = cal.startOfDayForDate(date) 
    let predicate = HKQuery.predicateForSamplesWithStartDate(newDate, endDate: NSDate(), options: .None) // Our search predicate which will fetch all steps taken today 

    // The actual HealthKit Query which will fetch all of the steps and add them up for us. 
    let query = HKSampleQuery(sampleType: type!, predicate: predicate, limit: 0, sortDescriptors: nil) { query, results, error in 
     var steps: Double = 0 

     if results?.count > 0 
     { 
      for result in results as! [HKQuantitySample] 
      { 
       steps += result.quantity.doubleValueForUnit(HKUnit.countUnit()) 
      } 
     } 

     completion(steps, error) 
    } 

    storage.executeQuery(query) 
} 
+2

Przepraszamy, ale to nie jest poprawne. HKSampleQuery zwraca każdy rekord kroku (nie usuwa duplikatów) i jest nieefektywnym sposobem obliczenia sumy próbek pasujących do predykatu. Powinieneś używać HKStatisticsQuery. – Allan

1

Stosując powyższe odpowiedzi i od Apple tutaj: https://developer.apple.com/reference/healthkit/hkstatisticsquery mam następujący pracować w szybkim 2.3 na Xcode 8.0 .

class func getStepCountHealth(startDate: NSDate, endDate: NSDate, completion:(Double?, NSError?)->()) { 

      let healthKitStore:HKHealthStore = HKHealthStore() 

      // Define the sample type 
      let sampleType = HKQuantityType.quantityTypeForIdentifier(
      HKQuantityTypeIdentifierStepCount) 

      // Set the predicate 
      let predicate = HKQuery.predicateForSamplesWithStartDate(startDate, 
                   endDate: endDate, options: .None) 
      // build the query 
      let sampleQuery = HKStatisticsQuery(quantityType: sampleType!, 
             quantitySamplePredicate: predicate, 
             options: .CumulativeSum) { query, results, error in 

             if results != nil { 
              let quantity = results?.sumQuantity() 
              let unit = HKUnit.countUnit() 
              let totalSteps = quantity?.doubleValueForUnit(unit) 
              completion(totalSteps, error) 
//           print("totalSteps for \(endDate) are \(totalSteps!)") 
             } else { 
              completion(nil, error) 
//           print("results are nil") 
              return 
             } 
            } 
      // execute the Query 
      healthKitStore.executeQuery(sampleQuery) 
     } 
8

HKStatisticsCollectionQuery jest lepiej przystosowany do użycia, gdy chcesz odzyskać dane w określonym przedziale czasowym. Użyj HKStatisticsQuery, aby uzyskać instrukcje dotyczące konkretnego dnia.

Swift 3 & 4:

let healthStore = HKHealthStore() 

    func getTodaysSteps(completion: @escaping (Double) -> Void) { 
     let stepsQuantityType = HKQuantityType.quantityType(forIdentifier: .stepCount)! 

     let now = Date() 
     let startOfDay = Calendar.current.startOfDay(for: now) 
     let predicate = HKQuery.predicateForSamples(withStart: startOfDay, end: now, options: .strictStartDate) 

     let query = HKStatisticsQuery(quantityType: stepsQuantityType, quantitySamplePredicate: predicate, options: .cumulativeSum) { (_, result, error) in 
      guard let result = result, let sum = result.sumQuantity() else { 
       log.error("Failed to fetch steps = \(error?.localizedDescription ?? "N/A")") 
       completion(0.0) 
       return 
      } 

      DispatchQueue.main.async { 
       completion(sum.doubleValue(for: HKUnit.count())) 
      } 
     } 

     healthStore.execute(query) 
    } 
+0

To rozwiązanie jest prostsze i wydajniejsze niż akceptowane. – chengsam