- 
                Notifications
    
You must be signed in to change notification settings  - Fork 457
 
Description
Hi, I was trying to schedule a notification based on the calorie burned during the day by the app user, so that only if the user had burned during the day less than 300 kcal (for example) by 8 in the evening, it would have scheduled the notification and sent it by that hour, otherwise it would have done nothing. However, I have lots of difficulties managing the schedule of the notification everyday only if the condition is met, which should be verified with query to the health store. and that's where things get worse, since the query is asynchronous.
here is a snippet of the code In tried so far, but it stop on the first day, and never check the condition again, nor schedule the notification:
`//    MARK: NOTIFICATION BASED ON HEALTHKIT DATA
func scheduleNotificationIfNeeded() {
let dispatchGroup = DispatchGroup()
let center = UNUserNotificationCenter.current()
let content = UNMutableNotificationContent()
content.title = "Reminder"
content.body = "You haven't burned enough calories today. Is that because you are experiencing severe pain? Come log it in!"
content.sound = .default
    let now = Date()
    let calendar = Calendar.current
    let year = calendar.component(.year, from: now)
    let month = calendar.component(.month, from: now)
    let day = calendar.component(.day, from: now)
    // Set the trigger date to 20:00 of the current day
    let dateComponents = DateComponents(year: year, month: month, day: day, hour: 20, minute: 0)
    let trigger = UNCalendarNotificationTrigger(dateMatching: dateComponents, repeats: false)
    let defaults = UserDefaults.standard
    if let lastScheduledDate = defaults.object(forKey: "lastScheduledNotificationDate") as? Date,
        Calendar.current.isDateInTomorrow(lastScheduledDate) {
        print("Notification already scheduled for tomorrow, skipping scheduling")
        return
    }
    dispatchGroup.enter()
    checkCaloriesBurned(forDate: Date()) { caloriesBurned in
        if caloriesBurned < 300 {
            let request = UNNotificationRequest(identifier: "CaloriesReminder", content: content, trigger: trigger)
            center.add(request) { error in
                if let error = error {
                    print("Error scheduling notification: \(error.localizedDescription)")
                } else {
                    let defaults = UserDefaults.standard
                    defaults.set(now, forKey: "lastScheduledNotificationDate")
                    print("Notification scheduled")
                }
            }
        } else {
            print("Calories burned is greater than or equal to 300, notification not scheduled")
            dispatchGroup.leave()
            DispatchQueue.main.asyncAfter(deadline: .now() + 24 * 60 * 60) {
                self.scheduleNotificationIfNeeded()
            }
        }
    }
    dispatchGroup.wait()
}
func checkCaloriesBurned(forDate date: Date, completion: @escaping (Double) -> Void) {
    let energyType = HKQuantityType.quantityType(forIdentifier: .activeEnergyBurned)!
    
    // Set the end date of the query to 20:00 of the current day
    let calendar = Calendar.current
    let endOfDay = calendar.date(bySettingHour: 20, minute: 0, second: 0, of: date)!
    let predicate = HKQuery.predicateForSamples(withStart: calendar.startOfDay(for: date), end: endOfDay, options: .strictEndDate)
    
    let query = HKStatisticsQuery(quantityType: energyType, quantitySamplePredicate: predicate, options: .cumulativeSum) { query, result, error in
        guard let result = result, let sum = result.sumQuantity() else {
            if let error = error {
                print("Error retrieving calories burned: \(error.localizedDescription)")
            }
            completion(0)
            return
        }
        let caloriesBurned = sum.doubleValue(for: HKUnit.kilocalorie())
        completion(caloriesBurned)
    }
    
    healthStore.execute(query)
}
`