iOS 10 - Repeating notifications every "x" minutes - ios

In iOS 10, how can I set local notifications to repeat in minutes starting from a particular date/time.
For example, trigger local notification every 15 minutes starting from 11 AM on 8th September? Assume that, below, dateTimeReminder.date has 09/08 11 AM.
let dateStart = self.dateTimeNotif.date
let notifTrigger = UNCalendarNotificationTrigger.init(dateMatching: NSCalendar.current.dateComponents([.day, .month, .year, .hour, .minute], from: dateStart), repeats: true)
let notificationRequest = UNNotificationRequest(identifier: "MYNOTIF", content: notifContent, trigger: notifTrigger)
UNUserNotificationCenter.current().add(notificationRequest, withCompletionHandler: nil)
With the above code, I have a possibility to schedule at a particular minute of every hour, at a particular hour of each day and so on. But how do I turn it into "every "x" minutes"? Any help is appreciated.
Similar question - How do I set an NSCalendarUnitMinute repeatInterval on iOS 10 UserNotifications?

Swift 3/4 and iOS 10/11:
According with this bug seems there is no way to use DateComponents() to repeat correctly a local notification.
Instead of this method you can change your trigger with TimeInterval (this method works if you interval is major than 60 seconds):
let thisTime:TimeInterval = 60.0 // 1 minute = 60 seconds
// Some examples:
// 5 minutes = 300.0
// 1 hour = 3600.0
// 12 hours = 43200.0
// 1 day = 86400.0
// 1 week = 604800.0
let trigger = UNTimeIntervalNotificationTrigger(
timeInterval: thisTime,
repeats: true)

As you are already aware, you can schedule maximum of 64 notifications per app. If you add more than that, the system will keep the soonest firing 64 notifications and will discard the other.
One way to make sure all notifications get scheduled is to schedule the first 64 notifications first, and then on regular time intervals (may be on every launch of the app or each time a notification fires) check for the number of notifications scheduled and if there are less than 64 notifications, lets say n notifications, then schedule the next (64 - n) notifications.
int n = [[[UIApplication sharedApplication] scheduledLocalNotifications] count];
int x = 64 - n;
// Schedule the next 'x' notifications
for rest add a NSTimer for X minutes to come and set the notification.
override func viewDidLoad() {
super.viewDidLoad()
//Swift 2.2 selector syntax
var timer = NSTimer.scheduledTimerWithTimeInterval(60.0, target: self, selector: #selector(MyClass.update), userInfo: nil, repeats: true)
//Swift <2.2 selector syntax
var timer = NSTimer.scheduledTimerWithTimeInterval(60.0, target: self, selector: "update", userInfo: nil, repeats: true)
}
// must be internal or public.
func setNotification() {
// Something cool
}
Make sure you remove old and not required notifications.

After searching around quite a bit, I've come to the conclusion that Swift 3, at this point, doesn't support this feature. For everyone looking for this functionality, I'd suggest using UILocalNotification for now (although deprecated in iOS 10), but later migrate to UNUserNotification once it supports this feature. Here are some additional questions and resources that have helped me to reach this conclusion. Also, please follow all the answers and comments in this thread to get more insight into which particular scenario it talks about.
It is usually a bad idea to use deprecated APIs. As a general practice, migrate to new APIs as soon as possible. The above solution is NOT recommended as a permanent solution.
Local Notification every 2 week
http://useyourloaf.com/blog/local-notifications-with-ios-10/
https://github.com/lionheart/openradar-mirror/issues/14941

This is how I set local notification based on time interval repeatedly and executed method customized snooze and delete
let content = UNMutableNotificationContent()
content.title = "Time Based Local Notification"
content.subtitle = "Its is a demo"
content.sound = .default
content.categoryIdentifier = "UYLReminderCategory"
//repition of time base local notification in foreground, background, killed
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 60, repeats: true)
let request = UNNotificationRequest(identifier: "IOS Demo", content: content, trigger: trigger)
UNUserNotificationCenter.current().add(request, withCompletionHandler: nil)
let snoozeAction = UNNotificationAction(identifier: "Snooze", title: "Snooze", options: [])
let deleteAction = UNNotificationAction(identifier: "UYLDeleteAction", title: "Delete", options: [.destructive])
let cat = UNNotificationCategory(identifier: "UYLReminderCategory", actions: [snoozeAction, deleteAction], intentIdentifiers: [], options: [])
UNUserNotificationCenter.current().setNotificationCategories([cat])

I think this thread has what you're looking for.
Do something every x minutes in Swift
The '60.0' represents seconds between the code running. Simply change that to x minutes * 60

The link you shared and the new details you added you need to save the last hour and minute of time for which notification got scheduled. Then when the timer ticks to next minute, there change the hour and minute
var date = DateComponents()
date.hour = 8
date.minute = 30
let trigger = UNCalendarNotificationTrigger(dateMatching: date, repeats: true)
let content = UNNotificationContent()
// edit your content
let notification = UNNotificationRequest(identifier: "myNotification", content: content, trigger: trigger)

You can first use the UNCalendarNotificationTrigger to trigger the notification at a particular date and set its repeat property to false so that it notifies only once. When you receive that notification, use the UNTimeIntervalNotificationTrigger API to set the time interval at which you want to trigger the local notification

Related

There is a way to set an notification to trigger in the first time in 8 hours and then in another time, like 4 in 4 hours in swift

I'm trying to make an algorithm that receives a time for the first dose of the medicine, and from there it triggers an alarm for X time from now, also selected by the user.
Example: First dose of the medicine was at 12:00 and I want to take it every 8 hours. Therefore, the first alarm must be set at 20:00 and the following, every 8 hours.
The problem is that if I set the first alarm to the desired time + 8, the alarm will not go off at 20, but yes. And if I only use it every 8 hours, I can't set the start time
func notifications(name: String, timeToTime: String, firstTime: String) {
let center = UNUserNotificationCenter.current()
getTimeForNotification(string: firstTime)
let content = UNMutableNotificationContent()
content.title = "It's time to take \(name)"
content.body = "Remember that you must ingest this medicine from \(timeToTime)"
content.sound = UNNotificationSound.default
let timeInterval = handleToInt(time: timeToTime) // * 3600
let trigger = UNTimeIntervalNotificationTrigger(
timeInterval: timeInterval,
repeats: true)
let request = UNNotificationRequest(identifier: name, content: content, trigger: trigger)
center.add(request)
}
first time is the variable that stores the time of the first dose, as a double, by the method getTimeForNotification() and timeInterval is the time, ex: 8 in 8, 12 in 12

Local notification cancel for particular time period

I want to fire local notification on a particular time based just liked water notification.
Like user can set wake up time & go to bed time n drink water notification for every 2 hours so how can i set that between goto bed to wake up time my local notification won;t fire, other than that the notification will fire for every 2 hours..
Please help me.
Thanks
What you can do is to obtain the hours in between the wake up time and sleep time with the frequency of what you wish your notification to fire off.
Firstly, you would need to function to create a local notification that repeats during a particular hour everyday.
func createNotification(title: String, body: String, hour: Int, repeats: Bool, identifier: String) {
//calendar
let calendar = Calendar.current
let content = UNMutableNotificationContent()
content.title = title
content.body = body
let today = Date()
let futureDate = calendar.date(byAdding: .hour, value: hour, to: today)
let hourComponent = calendar.dateComponents([.hour], from: futureDate!)
let trigger = UNCalendarNotificationTrigger(dateMatching: hourComponent, repeats: repeats)
let request = UNNotificationRequest(identifier: identifier, content: content, trigger: trigger)
center.add(request, withCompletionHandler: {(error) in })
}
Secondly, place this code in your viewDidLoad() or the place you wish to set the notifications. What I am doing here is obtaining the wakeup hour and sleep hour and then finding the number of notifications that has to be made using the frequency that I want by dividing the difference in hour with the frequency.
I end of by creating a for loop that creates the notification based on the time that I add to the wakeup hour. eg. First notification fires of at 6am + 1x2 = 8am, second notification fires of at 6am + 2x2 = 10am
//calendar
let calendar = Calendar.current
//set the wakeup and sleep hour
let wakeupHour = 6 //6am
let sleepHour = 18 // 6pm
//Obtain starting time using date components
let wakeup = DateComponents(calendar: calendar, hour: wakeupHour)
//Obtain ending time using date components
let sleep = DateComponents(calendar: calendar, hour: sleepHour)
//calculate the number of hours between the two time
//obtain number of hour difference
let hourDifference = calendar.dateComponents([.hour], from: wakeup, to: sleep)
//how many hours do you want
let frequency:Int = 2
//how many notifications will there be between the wakeup and sleeptime
let numberOfNotifications:Int = hourDifference.hour! / frequency
//create the notifications
for num in 1...numberOfNotifications {
//hour that each notification will fire off
let hour = wakeupHour + frequency * num
createNotification(title: "Drink Up", body: "Drink Up", hour: hour, repeats: true, identifier: "drink\(hour)")
}
I'm still learning swift so this may not be the most efficient way of solving this problem but I hope this helps!

Swift: Mute notifications for current day

in my app I send a daily notification to remind the user to visit the app.
This notification is locally delivered every day at 1pm.
func scheduleNotifications() -> Void {
for notification in notifications {
let content = UNMutableNotificationContent()
content.title = notification.title
let todaysDate = Date()
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "dd"
let currentDay = dateFormatter.string(from: todaysDate)
let currentDayInt = Int(currentDay) ?? 0
var datComp = DateComponents()
datComp.hour = 13
datComp.minute = 00
datComp.day = currentDayInt + 1
let trigger = UNCalendarNotificationTrigger(dateMatching: datComp, repeats: true)
let request = UNNotificationRequest(identifier: notification.id, content: content, trigger: trigger)
UNUserNotificationCenter.current().add(request) { error in
guard error == nil else { return }
print("Scheduling notification with id: \(notification.id) on Day \(datComp.day ?? 00) at \(datComp.hour ?? 00) - \(datComp.minute ?? 00)")
}
}
}
As you can see, I added the "current day + 1" lines because if the user opens the app before 1pm, there is no need to deliver the notification on this day.
So every time the user opens the app, I use UNUserNotificationCenter.current().removeAllPendingNotificationRequests() to remove and reschedule the notification for the next day (by recalling the function above).
My issue:
The notification should repeat every day, which it does, as long as the user opens the app.
But if the user does not open the app on one day, there will be no notification on the following days.
Is there a way to mute notifications for the current day so that I don't have to use this "current day + 1"-thing? Or does anyone have a better idea?
Thank you guys.
I think you misunderstood how repeating notifications and your datComp works here.
For example (let's use today's date: May 27)
datComp.hour = 13
datComp.minute = 00
datComp.day = currentDayInt + 1 // in our example it's 28
let trigger = UNCalendarNotificationTrigger(dateMatching: datComp, repeats: true)
means that your notification will get triggered every month on 28th, all parameters your trigger knows is hour, minute, day and by repeating it, will be triggered on every 28th at 13:00.
So the way your app works now is that you set up monthly notification starting from tomorrow, when you open the app you remove that monthly notification and reschedule it for day later. By opening every day it gives you impression that its daily notification but it's not, it's monthly. That's why if you don't open the app nothing shows up next the day, it will show up next month.
You can check my similar explanation here: (top answer there, maybe it is better worded and easier to understand)
Removing scheduled local notification
and my solution for similar problem i had here:
How to set up daily local notification for tasks but don't show it when user completes the task before

Repeat local notification every n days

I'm trying to create application that will send local notifications every n days.
I has DailyRepeat structure that contains notification info:
struct DailyRepeat: BaseRepeat {
var title: String
var body: String
var date: Date
var day: Int
}
And method that schedule notification:
func notifyDaily(at notification: DailyRepeat) {
let content = generateContent(title: notification.title, body: notification.body)
let dateComponents = DateComponents(day: notification.day, hour: notification.date.time.hours, minute: notification.date.time.minutes)
let trigger = UNCalendarNotificationTrigger(dateMatching: dateComponents, repeats: true)
let request = UNNotificationRequest(identifier: UUID().uuidString, content: content, trigger: trigger)
notificationCenter.add(request)
}
My first thought was to create UNCalendarNotificationTrigger on first fire date, than handle notification and set UNTimeIntervalNotificationTrigger, but unfortunately I cannot find the way to handle notification receive without user interaction.
Any thoughts how it should work?
As per the documentation if you want the notification to repeat you need to set repeatable constraints for the date components.
So to set a notification to run every morning at 8:30AM you would just set the hour and the minute and set it to repeat.
var date = DateComponents()
date.hour = 8
date.minute = 30
let trigger = UNCalendarNotificationTrigger(dateMatching: date, repeats: true)
I don't think that you can use repeats to repeat every x number of days, you can set specific days of the week, or dates of the month, but not every n days.
You could set a TimeInterval of x number of days and repeat that, but getting the exact time to start it might be tricky.

Swift 3 - user notification custom repeat like iOS Reminders app

I want to make an app just like iOS Reminders app. My problem is the custom repeat part. We can set custom repeats like "Every 2 Months on the third Monday"(the screenshot below) but I don't know how to implement this sort of repeats with User Notification.
What should I have do?
Although the question might be abroad to be fully answered, I would post an answer that should scratch the surface of how you could achieve it by using user notifications.
If you are aiming to let the displaying of the notification is based on a specific date/interval -as you mentioned "Every 2 Months on the third Monday"-, then you should work with UNCalendarNotificationTrigger:
The date and time at which to deliver a local notification.
Example:
import UserNotifications
// first, you declare the content of the notification:
let content = UNMutableNotificationContent()
content.title = "Notification Title"
content.subtitle = "Notification Subtitle"
content.body = "Notification Body"
// now, you should declare the UNCalendarNotificationTrigger instance,
// but before that, you'd need to describe what's the date matching for firing it:
// for instance, this means it should get fired every Monday, at 10:30:
var date = DateComponents()
date.weekday = 2
date.hour = 10
date.minute = 30
// declaring the trigger
let calendarTrigger = UNCalendarNotificationTrigger(dateMatching: date, repeats: true)
// creating a request and add it to the notification center
let request = UNNotificationRequest(identifier: "notification-identifier", content: content, trigger: calendarTrigger)
UNUserNotificationCenter.current().add(request)

Resources