2017-05-29 48 views
1

HKObserverQueryの設定で、バックグラウンドでステップを取得します(メソッドはapplication:didFinishLaunchingWithOptions:で呼び出されます)。HealthKitのバックグラウンドデリバリでステップを取得した後、バックグラウンドでFirebaseにデータを書き込む

ステップはバックグラウンドで取得されますが、取得したステップをFirebaseデータベースに保存することもできます。この部分は失敗しますが、Firebaseには何も保存されていません。アプリをフォアグラウンドにすると、ステップを保存するメソッドが正しく動作します。バックグラウンドでFirebaseにデータを書き込む方法に関するアイデアは高く評価されます。

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)") 
      } 
     } 
    } 

} 

答えて

4

これを解決しました。問題は、FireHabへの保存が実際に完了する前に、私が完了したことをHealthKitに伝えて、completionHandlerを呼び出すことでした。 Firebaseへの保存は非同期で行われます。

私はStepsManager.shared.updateUserSteps関数に完了ハンドラを追加しました:databaseRef.setValueが完了したときにトリガーされる

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

。次に、オブザーバークエリを次のように更新しました。

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

Firebaseの操作が正しく完了しました。

関連する問題