使用 swift 从 Health kit 获取今天的所有步数,但截断手动添加的步数
Getting all steps of today but truncating manually added steps, from Health kit using 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 中的。
我确实想要他们两个,我正在得到他们两个,但是当用户对 healthkit 进行一些手动步骤时,问题就来了。
我不想得到这些手动添加的步骤。所以基本上我想得到 (5,793 - 2300) = 3493 步。
我该怎么做?我试图获取 HKSource 的名称我知道当用户手动输入步骤时,源的名称是 "Health" 但我如何在此基础上过滤步骤?请指导我这件事,我在这里错过了什么?提前致谢
这可能不是最好的解决方案,但我相信它会奏效。您可以做的是获取所有使用 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))
})
}
})
首先配置HKSources,它指示我们必须从哪里获取健康数据。 (com.apple.health, com.apple.Health ...)
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
}
您应该创建 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)
})
}
我今天使用以下代码从 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 中的。
我确实想要他们两个,我正在得到他们两个,但是当用户对 healthkit 进行一些手动步骤时,问题就来了。
我不想得到这些手动添加的步骤。所以基本上我想得到 (5,793 - 2300) = 3493 步。
我该怎么做?我试图获取 HKSource 的名称我知道当用户手动输入步骤时,源的名称是 "Health" 但我如何在此基础上过滤步骤?请指导我这件事,我在这里错过了什么?提前致谢
这可能不是最好的解决方案,但我相信它会奏效。您可以做的是获取所有使用 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))
})
}
})
首先配置HKSources,它指示我们必须从哪里获取健康数据。 (com.apple.health, com.apple.Health ...)
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
}
您应该创建 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)
})
}