Cancel and reschedule UserNotification(old UILocalNotification) starting from custom date in iOS 10
Asked Answered
F

2

7

I'm scheduling a daily UserNorification to trigger everyday at a specific time, notifying the user to do something. But if the user does that X hours before the notification is fired, I need to cancel today's notification, in my opinion cancel all, and reschedule again but from tomorrow's specific time. For example, if today the notification should fire at 11:00 and the user "do that thing" at 10:00, the 11:00 notification should not be fired, and I need to schedule again at the same time but starting from tomorrow. And the cycle goes on and on, same for tomorrow. My questions are:

  1. Should I unschedule the first daily notifications using the following code: UNUserNotificationCenter.current().removeAllPendingNotificationRequests() ?

  2. How to schedule daily notifications starting from a specific date?

Farinaceous answered 17/12, 2016 at 19:10 Comment(7)
Are your notifications implementing a custom interface (i.e do you provide a UNNotificationContentExtension)?Bacterium
No, they just have title and body. Reminding the user to do something. But if he do that thing, 1 hour before the hardcoded 11:00, the notification should not be presented that day, but to continue the next day.Farinaceous
I have done that in previous notifcation framework. I atach some userinfo with each type of notiification and when the user perform the steps earlier.I retrieve that particular notificatio ,cancel it and re-register it with tommorow date.Sudarium
For now thats the only solution, using the old framework. But no need to send params in userInfo. The changes that the user can make it, are within the app, so when he do that, i will know whats the next notification and i will cancel it and reschedule for tomorrow.Farinaceous
but just for my learning how you know what notification you have to cancel. u have to give any identifier to it OR filter it through the date?Sudarium
Well you achieve both ways. I'm doing that with some math, currentTime.hours == firstNotFireHour -> cancel First. And respectively for every notification, because their date changes but hour dont.Farinaceous
I am converting the current time to seconds and the notification's time to seconds and subtract them to see if it is before or after it. Simple math. Then i cancel all of them and reschedule again regarding the product from subtracting.Farinaceous
F
0

After researching, this is not possible with the new UserNotifications Framework. We must use the old UILocalNotification approach to achieve this. Because that code is deprecated in iOS10, I've changed the supported version to be from 9+, so there will be no warnings. This is a permanent approach, but lets hope that Apple will implement and extend the old feature in the new framework.

Farinaceous answered 19/1, 2017 at 12:42 Comment(1)
Did you find any solution within the new framework?Pincince
B
3

Unfortunately, this kind of scheduling became ridiculously hard with the notifications framework in iOS 10. The only way I could find to do something similar is to use a hybrid of both UNCalendarNotificationTrigger and UNTimeIntervalNotificationTriggerAND implement a UNNotificationContentExtension.

The concept is the following:

Every time your action is being performed you need to reschedule your notifications. If the time is earlier than the desired notification time (e.g 11:00 in your example), instead of using a calendar trigger to reschedule, use a time interval trigger to set one, temporary, non-repeating notification for the next day (let's call it tempNotification)

let nextDayAt11AMDate = /* the timestamp of tomorrow at 11am */
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: nextDayAt11AMDate.timeIntervalSinceDate(NSDate()), repeats: false)
/* schedule tempNotification */

When this notification is received (and provided that a UNNotificationContentExtension has been implemented), in your extension's view controller didReceive: method which is called when the notification arrives, cancel existing notifications and schedule the actual, repeating notification normally using a calendar trigger (let's call it actualNoticfication)

let date = DateComponents()
date.hour = 11
date.minute = 00 
let trigger = UNCalendarNotificationTrigger(dateMatching: date, repeats: true)
/* schedule actualNotification */

It's a long work-around, probably not very efficient and also not 100% reliable (e.g if the device is closed when the tempNotification arrives then the actualNotification will not be scheduled) but it covers the majority of cases. I would be very glad to find a better way than that...

Bacterium answered 20/12, 2016 at 14:26 Comment(11)
So, when the app is suspended and tempNotification is received, the code will not be run, right? I guess there is no solution for this with the new Framework. But thanks for your effort.Farinaceous
@Farinaceous No, if the app is suspended the code will work; when a notification is received the content extension is triggered regardless of the state of the app. It's when the device is completely off that things get more complicated.Bacterium
Well in that case I will try the solution and if it works I will accept it. Just need to see how UNNotificationContentExtension works.Farinaceous
UNNotificationContentExtension is only used for devices that has/use 3D Touch. So in my case, with iPhone 6, i can't make it works... Or if you have some demo to show me, i will try it.Farinaceous
@Farinaceous UNNotificationContentExtension works for all iOS 10 devices (those that are not 3D Touch enabled can access the notification content by tapping on the view button). Regardless, you don't need to interact with the notification in order for the didReceive: to be invoked. I will try to provide some more code later (unfortunately it is an exceedingly busy day)Bacterium
I've implemented everything, the custom notification is showing, but didReceive is not called. Am I missing something?Farinaceous
Now I get it. It is getting called when i interact with the notification -> dragging down. Is there any way to trigger didReceive without interacting the notification?Farinaceous
I think you mean UNNotificationServiceExtension, not UNNotificationContentExtensionWeeks
@RizwanSattar the question is for local notifications, UNNotificationServiceExtension is available for remote notificationsBacterium
@Bacterium I see - so you have to implement a dummy UIViewController for the content extension which will actually show no UI, because didReceive: is called even without the notification being interacted with?Weeks
I'm getting the same problem with @Slavcho, that didReceive: is only called when the notification has been interacted with.Ecchymosis
F
0

After researching, this is not possible with the new UserNotifications Framework. We must use the old UILocalNotification approach to achieve this. Because that code is deprecated in iOS10, I've changed the supported version to be from 9+, so there will be no warnings. This is a permanent approach, but lets hope that Apple will implement and extend the old feature in the new framework.

Farinaceous answered 19/1, 2017 at 12:42 Comment(1)
Did you find any solution within the new framework?Pincince

© 2022 - 2024 — McMap. All rights reserved.