0

I want to get data from apple health on background.. I don't know where to call my function updateOnBackground

I looked on the related topics and I currently have this:

 func updateOnBackground() {
        
        let quantityType = HKQuantityType.quantityType(forIdentifier: .heartRate)!
        self.healthStore.enableBackgroundDelivery(for: quantityType, frequency: .immediate) { (success, error) in
            if let error = error {
                print("\(error)")
            }
            if success {
                print("background delivery enabled")
            }
        }
        
        let query = HKObserverQuery(sampleType: quantityType, predicate: nil) { (query, completionHandler, error) in
            self.updateData(){
                completionHandler()
            }
        }
        healthStore.execute(query)
        
    }

This is the function for getting the data while the app is active:

 class func getMostRecentSample(for sampleType: HKSampleType,
                                   completion: @escaping (HKQuantitySample?, Error?) -> Swift.Void) {
        let mostRecentPredicate = HKQuery.predicateForSamples(withStart: Date.distantPast, end: Date(), options: .strictEndDate)
        let sortDescriptor = NSSortDescriptor(key: HKSampleSortIdentifierStartDate, ascending: false)
        let limit = 1
        let sampleQuery = HKSampleQuery(sampleType: sampleType, predicate: mostRecentPredicate, limit: limit, sortDescriptors: [sortDescriptor]) { (query, samples, error) in
            DispatchQueue.main.async {
                guard let samples = samples,
                    
                    let mostRecentSample = samples.first as? HKQuantitySample else {
                        completion(nil, error)
                        
                        return
                }
                //print(samples)
                completion(mostRecentSample, nil)
            }
            
        }
        
        HKHealthStore().execute(sampleQuery)
    }
    func updateData(completionHandler: @escaping () -> Void) {
        let sampleType =  HKQuantityType.quantityType(forIdentifier: .heartRate)!
        HealthData.getMostRecentSample(for: sampleType) { (sample, error) in
            self.handleNewData(new: sample!)
            completionHandler()
        }
    }
    
    func handleNewData(new: HKQuantitySample) {
        print(new)
        
    }

I think function getMostRecentSample here is not needed, how else could i have done this better?

mag_zbc
  • 6,801
  • 14
  • 40
  • 62
yonix
  • 3
  • 3

1 Answers1

2

For observing queries and background deliveries, according to Apple docs https://developer.apple.com/documentation/healthkit/hkhealthstore/1614175-enablebackgrounddelivery there is no better place than inside AppDelegate.swift in the

func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
    updateOnBackground()
    return true
}

This will guarantee your app will receive a notification from Apple Health that the new data was generated. For some types the frequency of the updates can differ. For instance if you will try to fetch steps with .immediate frequency, this will not work - it will happen only after one hour (automatically decided by Apple Health App).

You may try out my CocoaPod. Here is the link: https://cocoapods.org/pods/HealthKitReporter. It is a wrapper above HealthKit framework to ease the reading/writing operations + observations.

You can also take a look (in a pod as well) at HKAnchoredObjectQuery implementation. It is like an observer query + sample query which also is a long-running query. Take a look here https://developer.apple.com/documentation/healthkit/hkanchoredobjectquery

Dharman
  • 30,962
  • 25
  • 85
  • 135
kvs
  • 141
  • 1
  • 7