Basically, I have an application where the user can set the time of the first notification, and the following ones will happen repeatedly. For example, I want to be notified every 8 hours, but the first notification will not be from now on. So I need to create 2 notifications, one for the first one, and as soon as the first one goes off, I need to set a new notification every 8 hours.
A practical example: I will take my medicine at 8 o'clock in the morning, but now it's 5 o'clock, and I want to be notified every 8 hours. The first alarm must be for 8 o'clock from 8 o'clock, that is, 4 o'clock. For that, I made a logic:
However, the other alarms cannot have the same time as the first one, because, as in the previous example, if I left the same trigger, the alarms would be 11 hours, not 8. I need the first to be 11 hours, and the subsequent numbers of 8 in the example.
I already have the code for the first alarm, however, I can't think of a way to create the subsequent ones, which will keep repeating according to the desired time, for example, 8 in 8, 12 in 12
CodePudding user response:
You need to setup a BGAppRefreshTask
, which will tell the System to periodically wake your app to run in the Background to do something in about 30 seconds, then app is Suspended.
You can set a Refreshing Task every 6 hours to check and make a new Local Push Notification if needed.
Here is the guide: https://developer.apple.com/documentation/uikit/app_and_environment/scenes/preparing_your_ui_to_run_in_the_background/using_background_tasks_to_update_your_app
When you setup your local notification:
// Create the request
let uuidString = UUID().uuidString // SAVE this one to UserDefault then you can fetch delivered/pending notification if needed.
let request = UNNotificationRequest(identifier: uuidString,
content: content, trigger: trigger)
// Schedule the request with the system.
let notificationCenter = UNUserNotificationCenter.current()
notificationCenter.add(request) { (error) in
if error != nil {
// Handle any errors.
}
}
Function in your AppDelegate.swift
// Here you register it in didFinishLaunching()
BGTaskScheduler.shared.register(forTaskWithIdentifier: "com.example.apple-samplecode.ColorFeed.refresh", using: nil) { task in
self.handleAppRefresh(task: task as! BGAppRefreshTask)
}
// Func to register a next background refresh task
func scheduleAppRefresh() {
let request = BGAppRefreshTaskRequest(identifier: "com.example.apple-samplecode.ColorFeed.refresh")
// Fetch no earlier than 15 minutes from now.
request.earliestBeginDate = Date(timeIntervalSinceNow: 15 * 60)
do {
try BGTaskScheduler.shared.submit(request)
} catch {
print("Could not schedule app refresh: \(error)")
}
}
// Here is where you do your logic when the app runs by background refresh event.
func handleAppRefresh(task: BGAppRefreshTask) {
// Schedule a new refresh task.
scheduleAppRefresh()
// Create an operation that performs the main part of the background task.
let operation = RefreshAppContentsOperation() // you dont really need this one, just call your logic here.
// Ex:
UNUserNotificationCenter.current().getDeliveredNotifications {[weak self] listNoti in
for noti in listNoti {
if noti.identifier == [your UUID that you just save in UserDefault before] {
// It delivered, now make new Local notification...
}
}
}
// Provide the background task with an expiration handler that cancels the operation.
task.expirationHandler = {
operation.cancel()
}
// Inform the system that the background task is complete
// when the operation completes.
operation.completionBlock = {
task.setTaskCompleted(success: !operation.isCancelled)
}
// Start the operation.
operationQueue.addOperation(operation)
}
CodePudding user response:
Use a repeating UNCalendarNotificationTrigger
for each separate time of day. In your case, that means use three triggers (and therefore three requests): one each at 8, 16, and 0 hours. You don't need to add a separate request for the soonest occurrence.
for i in 0 ..< 3 {
let when = DateComponents(hour: (8 8 * i) % 24, minute: 0)
let trigger = UNCalendarNotificationTrigger(dateMatching: when, repeats: true)
let request = UNNotificationRequest(
identifier: "trigger-\(i)",
content: someContent(),
trigger: trigger
)
UNUserNotificationCenter.current().add(request) { error in
if let error = error {
// handle error
}
}
}