Получение всех сегодняшних шагов, но усечение добавленных вручную шагов из Health Kit с использованием swift

Сегодня я получаю шаги от HealthKit, используя приведенный ниже код.

    func retrieveStepCount(completion: (stepRetrieved: Double) -> Void) {
         let type = HKSampleType.quantityTypeForIdentifier(HKQuantityTypeIdentifierStepCount) 

    let date = NSDate()
    let cal = NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian)!
    let newDate = cal.startOfDayForDate(NSDate())

    let predicate = HKQuery.predicateForSamplesWithStartDate(newDate, endDate: NSDate(), options: .None) // Our search predicate which will fetch all steps taken today
    let interval: NSDateComponents = NSDateComponents()
    interval.day = 1

    let query = HKStatisticsCollectionQuery(quantityType: type!, quantitySamplePredicate: predicate, options: .CumulativeSum, anchorDate: newDate as NSDate, intervalComponents:interval as NSDateComponents)

    query.initialResultsHandler = { query, results, error in

        if error != nil {

            print("Something went Wrong")
            return
        }
        if let myResults = results{
            myResults.enumerateStatisticsFromDate(newDate, toDate: NSDate()) {
                statistics, stop in
                if let quantity = statistics.sumQuantityForSource(HKSource.defaultSource()) {

                    let steps = quantity.doubleValueForUnit(HKUnit.countUnit())

                    print("Steps = \(Int(steps))")
                    completion(stepRetrieved: steps)
                }
            }
        }
    }
    executeQuery(query)
}

Теперь скажем, у меня есть эти шаги в общей сложности

введите здесь описание изображения

Из которого у меня есть несколько шагов, которые были автоматически обнаружены устройством. а некоторые были добавлены другим приложением в heathkit.

введите здесь описание изображения

Мне нужны оба из них, и я получаю их оба, но проблема возникает, когда пользователь выполняет какие-то действия вручную для набора здоровья.

введите здесь описание изображения

Я не хочу получать эти добавленные вручную шаги. Итак, в основном я хочу получить (5 793 - 2300) = 3493 шага.

Как я могу это сделать ? Я пытался получить имя HKSource. Я знаю, что когда пользователь вводит шаги вручную, имя источника — «Здоровье», но как мне фильтровать шаги на этой базе? Пожалуйста, расскажите мне об этом, и что мне здесь не хватает? заранее спасибо


person Byte    schedule 25.08.2016    source источник


Ответы (3)


Возможно, это не лучшее решение, но я верю, что оно сработает. Что вы можете сделать, так это получить все шаги, которые были добавлены вручную с помощью HKSampleQuery. вот пример.

 func todayManuallyAddedStepsSteps(completion: (Double, NSError?) -> () )
    {

    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]
            {
                print("Steps \(result.quantity.doubleValueForUnit(HKUnit.countUnit()))")
                print()

                // checking and adding manually added steps
                if result.sourceRevision.source.name == "Health" {
                    // these are manually added steps
                    print(result.sourceRevision.source.name)
                    print("Steps \(result.quantity.doubleValueForUnit(HKUnit.countUnit()))")
                    steps += result.quantity.doubleValueForUnit(HKUnit.countUnit())
                }
                else{
                    // these are auto detected steps which we do not want from using HKSampleQuery
                }
            }
            print(steps)
        }
        completion(steps, error)
    }

    executeQuery(query)
}

а затем получите общее количество шагов за сегодня, используя HKStatisticsCollectionQuery, как показано ниже.

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

    let type = HKSampleType.quantityTypeForIdentifier(HKQuantityTypeIdentifierStepCount) // The type of data we are requesting

    let calendar = NSCalendar.currentCalendar()
    let interval = NSDateComponents()
    interval.day = 1

    let anchorComponents = calendar.components([.Day , .Month , .Year], fromDate: NSDate())
    anchorComponents.hour = 0
    let anchorDate = calendar.dateFromComponents(anchorComponents)

    let stepsQuery = HKStatisticsCollectionQuery(quantityType: type!, quantitySamplePredicate: nil, options: .CumulativeSum, anchorDate: anchorDate!, intervalComponents: interval)

    stepsQuery.initialResultsHandler = {query, results, error in
        let endDate = NSDate()
        let startDate = calendar.dateByAddingUnit(.Day, value: 0, toDate: endDate, options: [])
        if let myResults = results{  myResults.enumerateStatisticsFromDate(startDate!, toDate: endDate) { statistics, stop in
            if let quantity = statistics.sumQuantity(){
                let date = statistics.startDate
                let steps = quantity.doubleValueForUnit(HKUnit.countUnit())
                print("\(date): steps = \(steps)")
                completion(stepRetrieved: steps)
            }
            }
        }
    }
    executeQuery(stepsQuery)
}

Теперь вы можете вызывать эти методы и вычитать добавленные вручную шаги, как показано ниже.

todayManuallyAddedSteps({ (steps , error) in
            if error != nil{
                print(error)
            }
            else{
                // truncating manuall steps
                TodayTotalSteps({ (stepRetrieved) in
                    // steps without manuall steps
                    print(Int(stepRetrieved - steps))

                })
            }
        })
person Umair Afzal    schedule 28.08.2016
comment
ооо я об этом не подумала. Спасибо !! - person Byte; 28.08.2016
comment
возвращать неверные данные, когда реклама Apple Watch вмешивается в Health. Сначала извлеките весь источник и создайте новый запрос относительно этого источника. - person Alisher; 25.03.2021

Вы должны создать предикат HKSourceQuery и соединить его с предикатом, который вы хотите использовать. В моем случае я сделал

fileprivate static func configureSourcePredicate(identifier: HKQuantityTypeIdentifier, completion: @escaping(NSPredicate?) -> Void) {
var deviceSources : Set<HKSource> = Set()
let appleHealth = "com.apple.health"
let handler : (HKSourceQuery, Set<HKSource>?, Error?) -> Void = { query , sources , error in
    if sources == nil || error != nil {
        completion(nil)
        return
    }
    for source in sources! {
        if source.bundleIdentifier.hasPrefix(appleHealth){
            deviceSources.insert(source)
        }
    }
    completion(HKQuery.predicateForObjects(from: deviceSources))
}
let sampleType = HKQuantityType.quantityType(forIdentifier: identifier)
let sourceQuery = HKSourceQuery(sampleType: sampleType!, samplePredicate: nil, completionHandler: handler)
healthStore?.execute(sourceQuery)
}

fileprivate static func request(type identifier: HKQuantityTypeIdentifier, startDate : Date, interval : DateComponents, completion : @escaping(TYPE_OF_DATA) -> Void) {
configureSourcePredicate(identifier: identifier, completion: { sourcePredicate in
    let type = HKSampleType.quantityType(forIdentifier: identifier)
    var predicate = HKQuery.predicateForSamples(withStart: startDate, end: Date(), options: [.strictStartDate, .strictEndDate])
    if sourcePredicate != nil {
        predicate = NSCompoundPredicate(andPredicateWithSubpredicates: [predicate , sourcePredicate!])
    }
    let query = HKStatisticsCollectionQuery(quantityType: type!, quantitySamplePredicate: predicate, options: [.cumulativeSum], anchorDate: Date(), intervalComponents: interval)
    query.initialResultsHandler = { query, results, error in
        if error != nil || results == nil {
            return
        }
        //your code here
        DispatchQueue.main.async {
            completion(RETURNED_DATA)
        }
    }
    healthStore?.execute(query)
})
}
person Alexandr Kolesnik    schedule 13.04.2017

Сначала настройте HKSources, который указывает, откуда мы должны получить данные о работоспособности. (ком.яблоко.здоровье, ком.яблоко.Здоровье...)

func configureSourcePredicate() {

    self.queryGroup = DispatchGroup()
    self.deviceSources = Set()

    //Only get the health data from the apple health without manually added steps
    let appleHealth = "com.apple.health"
    self.queryGroup?.enter()
    let sourcesQueryCompletionHandler : CompletionBlock = { (query , sources , error) in
         s
        if let deviceSourcesLocal = sources    {
            for source in deviceSourcesLocal {
                if source.bundleIdentifier.hasPrefix(appleHealth){
                    self.deviceSources?.insert(source)
                    print("Device sources are \(source.bundleIdentifier)")
                }
            }
            self.queryGroup?.leave()
        }
    }

    let sampleType = HKQuantityType.quantityType(forIdentifier: HKQuantityTypeIdentifier.stepCount)
    let sourceQuery = HKSourceQuery(sampleType: sampleType!, samplePredicate: nil, completionHandler: sourcesQueryCompletionHandler)
    self.healthStore.execute(sourceQuery)

    self.queryGroup?.notify(queue: DispatchQueue.global(), execute: { 
        self.todayTotalSteps()
    })  }

//Доступ к подсчету шагов из источников данных

func todayTotalSteps() {

    let completionHandler: (HKStatisticsQuery, HKStatistics?, Error?) -> Void = {
        (_query, result, error) -> Void in
         DispatchQueue.main.async {
            print("Result is \(result)")

            if let quantity: HKQuantity = result?.sumQuantity() {

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

                print("Steps = \(steps)")

                self.stepsCount.text = "\(steps)"
                self.queryGroup?.leave()
            }
         }
    }

    let stepsCount = HKQuantityType.quantityType(forIdentifier: .stepCount)
    let predicate = predicateForSamplesToday()
    self.queryGroup?.enter()
    let query = HKStatisticsQuery(quantityType: stepsCount!, quantitySamplePredicate: predicate, options: HKStatisticsOptions.cumulativeSum, completionHandler: completionHandler)

    if (self.healthStore) != nil {
        self.healthStore.execute(query)
    }}

//Создание предиката

private func predicateForSamplesToday() -> NSPredicate
{
    print("Device sources \(self.deviceSources)")
    let (starDate, endDate): (Date, Date) = self.datesFromToday()

    var predicate: NSPredicate = HKQuery.predicateForSamples(withStart: starDate, end: endDate, options: HKQueryOptions.strictStartDate)

    if deviceSources == self.deviceSources {
        predicate = NSCompoundPredicate(andPredicateWithSubpredicates: [predicate , HKQuery.predicateForObjects(from: deviceSources!)])
    }

    return predicate
}
person Swifty    schedule 23.03.2017