Skip to content

Trying to schedule a notification based on the caloriesBurned only if they are less than a certain amount (with query to the health store) #686

@federicatopazio

Description

@federicatopazio

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

`

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions