2017-05-29 1 views
1

J'ai une configuration HKObserverQuery pour récupérer les étapes en arrière-plan (la méthode enableBackgroundDelivery est appelée en application:didFinishLaunchingWithOptions:).Ecriture des données dans Firebase en arrière-plan après récupération des étapes avec la livraison d'arrière-plan de HealthKit

Les étapes sont récupérées en arrière-plan, mais je voudrais également stocker les étapes récupérées dans une base de données Firebase. Cette partie échoue cependant, rien n'est stocké dans Firebase. La méthode de stockage des étapes fonctionne correctement lorsque l'application est au premier plan. Toute idée sur la façon d'écrire avec succès des données dans Firebase en arrière-plan serait appréciée.

class HealthKitManager { 

    static let shared = HealthKitManager() 
    private let healthStore = HKHealthStore() 
    private let stepsQuantityType = HKQuantityType.quantityType(forIdentifier: .stepCount)! 

    private init() { 

    } 

    func getTodaysStepCount(completion: @escaping (Double) -> Void) { 
     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 
      var resultCount = 0.0 

      guard let result = result else { 
       log.error("Failed to fetch steps = \(error?.localizedDescription ?? "N/A")") 
       completion(resultCount) 
       return 
      } 

      if let sum = result.sumQuantity() { 
       resultCount = sum.doubleValue(for: HKUnit.count()) 
      } 

      DispatchQueue.main.async { 
       completion(resultCount) 
      } 
     } 

     healthStore.execute(query) 
    } 

    func enableBackgroundDelivery() { 
     let query = HKObserverQuery(sampleType: stepsQuantityType, predicate: nil) { [weak self] (query, completionHandler, error) in 
      if let error = error { 
       log.error("Observer query failed = \(error.localizedDescription)") 
       return 
      } 

      self?.getTodaysStepCount(completion: { steps in 
       // Store steps using Firebase: 
       StepsManager.shared.updateUserSteps(steps) 
       completionHandler() 
      }) 
     } 

     healthStore.execute(query) 
     healthStore.enableBackgroundDelivery(for: stepsQuantityType, frequency: .hourly) { (success, error) in 
      log.debug("Background delivery of steps. Success = \(success)") 

      if let error = error { 
       log.error("Background delivery of steps failed = \(error.localizedDescription)") 
      } 
     } 
    } 

} 

Répondre

4

Ok, j'ai résolu ceci. Le problème était que j'appelais le completionHandler, disant à HealthKit que j'en avais fini avec mon opération, avant que l'enregistrement dans Firebase ne soit terminé. L'enregistrement dans Firebase est effectué de manière asynchrone.

I a ajouté un gestionnaire d'exécution de la fonction StepsManager.shared.updateUserSteps:

func updateUserSteps(_ steps: Double, withCompletion completion: (() -> Void)? = nil) { 
    let stepsReference = databaseInstance.reference(withPath: stepsPath) 
    stepsReference.setValue(steps) { (error, _) in 
     if let completion = completion { 
      completion() 
     } 
    } 
} 

qui est déclenché lorsque le databaseRef.setValue est terminée. J'ai ensuite mis à jour la requête d'observateur à la suivante:

self?.getTodaysStepCount(completion: { steps in 
    StepsManager.shared.updateUserSteps(steps) { 
     completionHandler() 
    } 
}) 

L'opération Firebase se termine correctement maintenant.