Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get walking and running distance using HealthKit in swift

I'm making Health App. I want to get walkingRunningDistance from HealthKit in Swift. But, I have a problem. Return value is 0.0mile.

Why return value is 0 mile?

My code is this.

func recentSteps3(completion: (Double, NSError?) -> () ){
    let type = HKSampleType.quantityTypeForIdentifier(HKQuantityTypeIdentifierDistanceWalkingRunning)

    let date = NSDate()

    let cal = NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian)!

    let newDate = cal.startOfDayForDate(date)

    let predicate = HKQuery.predicateForSamplesWithStartDate(newDate, endDate: NSDate(), options: HKQueryOptions.StrictStartDate)

    let query = HKSampleQuery(sampleType: type!, predicate: predicate, limit: HKObjectQueryNoLimit, sortDescriptors: nil) { query, results, error in

        var distance: Double = 0

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

        completion(distance, error)
    }

    healthAuth.healthStore.executeQuery(query)
}
like image 614
Sung-jun Kim Avatar asked Dec 25 '22 05:12

Sung-jun Kim


2 Answers

Your code will return a value if

  1. You have requested permission from the user to read distanceWalkingRunning from HealthKit
  2. The user has granted your app permission.

If not, your code will return 0.

To request authorization, you can call

func requestAuthorization(toShare typesToShare: Set<HKSampleType>?, read typesToRead: Set<HKObjectType>?, completion: @escaping (Bool, Error?) -> Swift.Void)

where typesToRead contains

let distanceType =  HKSampleType.quantityType(forIdentifier: HKQuantityTypeIdentifier.distanceWalkingRunning)!

I believe that using a HKStatisticsQuery or HKStatisticsCollectionQuery will be more efficient. Here is an example.

guard let type = HKSampleType.quantityType(forIdentifier: .distanceWalkingRunning) else {
    fatalError("Something went wrong retriebing quantity type distanceWalkingRunning")
}
let date =  Date()
let cal = Calendar(identifier: Calendar.Identifier.gregorian)
let newDate = cal.startOfDay(for: date)

let predicate = HKQuery.predicateForSamples(withStart: newDate, end: Date(), options: .strictStartDate)

let query = HKStatisticsQuery(quantityType: type, quantitySamplePredicate: predicate, options: [.cumulativeSum]) { (query, statistics, error) in        
    var value: Double = 0

    if error != nil {
        print("something went wrong")
    } else if let quantity = statistics?.sumQuantity() {
        value = quantity.doubleValue(for: HKUnit.mile())
    }
    DispatchQueue.main.async {
        completion(value)
    }
}
healthStore.execute(query)
like image 180
Carien van Zyl Avatar answered May 16 '23 07:05

Carien van Zyl


For Swift 4.1

After enabled the HealthKit in your project's capabilities and added the necessary "Privacy - Health Share Usage Description" key to your info.plist file...

Ensure you are requesting for the approval of the user by adding this to the ViewController.swift, practically in the viewDidLoad() function.

    let store = HKHealthStore()

    let stepType = HKQuantityType.quantityType(forIdentifier: .stepCount)!
    let woType = HKObjectType.workoutType()

    store.requestAuthorization(toShare: [], read: [stepType, woType], completion: { (isSuccess, error) in
        if isSuccess {
            print("Working")
            self.getSteps()
        } else {
            print("Not working")
        }
    })

Then create the getSteps() function.

func getSteps() {
    let startDate = Calendar.current.date(bySettingHour: 0, minute: 0, second: 0, of: Date())!

    let endDate = Date()

    print("Collecting workouts between \(startDate) and \(endDate)")

    let predicate = HKQuery.predicateForSamples(withStart: startDate, end: endDate, options: HKQueryOptions.strictEndDate)

    let query = HKSampleQuery(sampleType: HKQuantityType.quantityType(forIdentifier: .distanceWalkingRunning)!, predicate: predicate, limit: HKObjectQueryNoLimit, sortDescriptors: nil) { (query, results, error) in
        for item in results! {
            print(item)
        }
    }

    store.execute(query)
}
like image 30
KZD76 Avatar answered May 16 '23 05:05

KZD76