I know this has been asked several times but there is no concrete solution I have found over the SO.I am working on iOS app and I am using userNotification and all things are working fine but then I have to use the recurring/repeat notifications so here are the conditions that I have to fulfill and wondering how
Case: Show notification to user to check for specific task if it is completed.
show notification everyday until specified date is arrived
Show notification every monday until specified date is arrived
Show notification monthly every specified day until specifed date is arrived
Problem:
I do not know how to schedule repeat notification for given conditions
Is there any limit of notification per app? suppose I have 100 of task and each task may have any of the notification bounded with the uppar given conditions.
Please tell me what could be done? and how I can fulfill my requirements.
show notification everyday until specified date is arrived
This is to display a message at a specific time every day
var dateComponents = DateComponents()
dateComponents.hour = 10
dateComponents.minute = 30
let trigger = UNCalendarNotificationTrigger(dateMatching: dateComponents, repeats: true)
if trigger.nextTriggerDate() >= your_specified_date {
return
}
Is there any limit of notification per app? suppose I have 100 of task
and each task may have any of the notification bounded with the uppar
given conditions.
Yes, there are limits. The system keeps the soonest-firing 64 notifications (with automatically rescheduled notifications counting as a single notification) and discards the rest.
Notification schedule for custom date with body
func schedulingNotificationForCustomDate(body: String, currentDate: Date) {
// Configure User Notification Center
let center = UNUserNotificationCenter.current()
let content = UNMutableNotificationContent()
content.title = ""
content.subtitle = ""
content.body = body
content.categoryIdentifier = "WeekDay notification"
content.userInfo = ["NotificationID": "WeekDay notification", "repeat": true, "reschedule": false]
content.sound = UNNotificationSound.default
let trigger = UNTimeIntervalNotificationTrigger.init(timeInterval: currentDate.timeIntervalSince1970, repeats: true)
let request = UNNotificationRequest(identifier: "WeekDay notification", content: content, trigger: trigger)
center.add(request, withCompletionHandler: nil)
}
Create date as per requirement
extension Date {
static func createDate(weekday: Int, hour: Int, minute: Int, year: Int) -> Date {
let calendar = Calendar.current
var components = DateComponents()
components.hour = hour
components.minute = minute
components.year = year
components.month = calendar.component(.month, from: Date())
components.day = calendar.component(.day, from: Date())
components.weekday = weekday // sunday = 1 ... saturday = 7
components.timeZone = .current
return calendar.date(from: components)!
}
}
Get the next date for scheduling repeat notification
extension Date {
static func nextNthDateFromCurrentDate(FromDate: Date, numberOfDays: Int) -> Date {
return Calendar.current.date(byAdding: .day, value: numberOfDays, to: FromDate)! // where numberOfDays is the number of days for the next date
}
}
For scheduling notification call
self.schedulingNotificationForCustomDate(body: body, currentDate: Date.nextNthDateFromCurrentDate(FromDate: Date.createDate(weekday: 2, hour: 11, minute: 00, year: year), numberOfDays: 14))
There is no end date specification on repeating local notifications, so unfortunately you will need to build something custom. However this is a limit of 64 notifications you may queue up according to Apple.
An app can have only a limited number of scheduled notifications; the
system keeps the soonest-firing 64 notifications (with automatically
rescheduled notifications counting as a single notification) and
discards the rest.
I would have an extension that can grab the dates between two dates like so:
extension Date {
static func dates(from fromDate: Date, to toDate: Date) -> [Date] {
var dates: [Date] = []
var date = fromDate
while date <= toDate {
dates.append(date)
guard let newDate = Calendar.current.date(byAdding: .day, value: 1, to: date) else { break }
date = newDate
}
return dates
}
}
Then you can grab the dates that you need and iterate through each one to create a notification:
let threeDaysFromNowExample = Calendar.current.date(byAdding: .day, value: 3, to: Date())!
let dates = Date.dates(from: Date(), to: threeDaysFromNowExample)
for date in dates {
let notification = UILocalNotification()
notification.fireDate = date
notification.alertBody = "Your alert here!"
notification.soundName = UILocalNotificationDefaultSoundName
UIApplication.shared.scheduleLocalNotification(notification)
}
Did not test this code, but should get you started. You may need to massage the extension some to add the ability to grab only Mondays for example.
Related
The use case is that there is a form where a user can say: I want to get a notification on X days (e.g Monday, Friday and Sunday) at 14:00. The application is in react native but I'm just calling a native swift function to schedule the notification:
import Foundation
import UserNotifications
#objc(Reminders)
class Reminders: NSObject {
#objc func setReminder(
_ message: NSString,
daysV days: NSArray,
hourV hour: NSInteger,
minuteV minute: NSInteger
) {
// We'll replace all scheduled notifications entirely
UNUserNotificationCenter.current().removeAllPendingNotificationRequests()
// Create a notification for each day that has been passed
let daysC: [Int] = days.map { $0 as! Int }
for day in daysC {
var date = DateComponents()
date.weekday = day
date.hour = hour
date.minute = minute
let content = UNMutableNotificationContent()
content.title = "Reminder"
content.body = message as String
let userCalendar = Calendar(identifier: .iso8601)
let dateTime = userCalendar.date(from: date)
let triggerDate = Calendar.current.dateComponents([.weekday,.hour,.minute], from: dateTime as! Date)
let trigger = UNCalendarNotificationTrigger(dateMatching: triggerDate, repeats: true)
let identifier = "TMWTE\(day)"
let request = UNNotificationRequest(identifier: identifier, content: content, trigger: trigger)
let center = UNUserNotificationCenter.current()
center.add(request, withCompletionHandler: { (error) in
if let error = error {
print(error);
}
})
}
}
}
What I'm trying to do is get each of the weekday included in a list sent from JS and schedule a notification for it. So if the user selects Monday and Wednesday the array will be [1,3] and I'll schedule a notification for each day respectively.
What's actually happening however is that I get X notifications at once in the first day. Thus if the user selects all days then in the next triggerDate I'll get 7 notifications.
Being a complete novice in Swift I may be doing something irrational, but I cannot figure it out at the moment. Now I've also tried to set the date.day to be the next Saturday, Sunday etc.. but that causes no notifications to be shown, which makes me think that I'm missing something basic here.
Thanks!
I tried to repeat a notification with UNCalendarNotificationTrigger(dateMatching:, repeats:), but this method can only repeat at a certain time.
I also tried UNTimeIntervalNotificationTrigger(timeInterval:, repeats:) and repeated a notification by a time interval, but this method could not set the start time of push notification.
And these two methods seems that there is no place to set a time for end push notifications.
I want to start with a special time and repeat notifications at regular intervals. What should I do?
Rather than using the repeats parameter you could loop from your start time to end time scheduling individual notifications.
let notifIDPrefix = "mynotif"
let notifCategory = "com.mydomain.mynotif" // this should have been registered with UNUserNotificationCenter
func scheduleNotifs(from startDate: Date, to endDate: Date, with interval: TimeInterval) {
var curDate = startDate
var count: Int = 0
while curDate.compare(endDate) != .orderedDescending {
scheduleNotif(with: "\(notifIDPrefix)_\(count)", date: curDate)
curDate = curDate.addingTimeInterval(interval)
count += 1
}
}
private func scheduleNotif(with identifier: String, date: Date) {
let content = UNMutableNotificationContent()
content.title = "My Title"
content.body = " "
content.categoryIdentifier = notifCategory
content.sound = UNNotificationSound.default()
let triggerTime = Calendar.current.dateComponents([.year, .day, .hour, .minute, .second], from: date)
let trigger = UNCalendarNotificationTrigger(dateMatching: triggerTime, repeats: false)
let request = UNNotificationRequest(identifier: identifier, content: content, trigger: trigger)
let center = UNUserNotificationCenter.current()
center.add(request) { (error : Error?) in
if let theError = error {
print(theError.localizedDescription)
}
}
}
The following would schedule 3 notifications (1, 2, and 3 minutes from now).
let startDate = Date().addingTimeInterval(60)
let endDate = startDate.addingTimeInterval(60 * 2)
let interval: TimeInterval = 60
scheduleNotifs(from: startDate, to: endDate, with: interval)
I want to show local notifications to user between selected hours from user and repeat that notification for every half hour till the limit of the selected hour comes and also repeat this notification daily.
I have used this code
let components = calendar.dateComponents(in: .current, from: date)
var triggerDate = DateComponents()
triggerDate.hour = components.hour
triggerDate.minute = components.minute
let trigger = UNCalendarNotificationTrigger(dateMatching: triggerDate, repeats: true)
But this only repeats the notification daily at that specific time selected by user but I want to repeat this also at every half hour from that specific time.I have used UNNotifications.Any help will be much appreciated.Thanks
If you want to show local notifications for every half hour between selected hours then you have to set different notification for every hour with different notification identifier as:
var dateStart = "Pass Your Start Date for Notification."
let dateEnd = "Pass Your End Date for Notification."
//Check Start Date is less then End Date is not.
while dateStart < dateEnd {
dateStart = dateStart.addingTimeInterval(0.5 * 60 * 60) //Add half an hour to start time
//Schedule notification With body and title.
scheduleNotification(at: dateStart, body: "Show Me", titles: "Remainder")
}
Implement Notification by following function as:
//Schedule Notification with Daily bases.
func scheduleNotification(at date: Date, body: String, titles:String) {
let triggerDaily = Calendar.current.dateComponents([.hour,.minute,.second], from: date)
let trigger = UNCalendarNotificationTrigger(dateMatching: triggerDaily, repeats: true)
let content = UNMutableNotificationContent()
content.title = titles
content.body = body
content.sound = UNNotificationSound.default()
content.categoryIdentifier = "todoList"
let request = UNNotificationRequest(identifier: "NotificationAt-\(date))", content: content, trigger: trigger)
UNUserNotificationCenter.current().delegate = self
//UNUserNotificationCenter.current().removeAllPendingNotificationRequests()
UNUserNotificationCenter.current().add(request) {(error) in
if let error = error {
print("Uh oh! We had an error: \(error)")
}
}
}
Pass start Date in dateStart variable and Date End Date in dateEnd variable.
I have an array containing my dates. I want to schedule notifications for those days at 6.30am.
I followed the appcoda tutorial which helps scheduling the notification upon input from a datepicker which is great, but I am a bit uncertain on how to call my function to schedule the notification for only the given days.
So my question is how and where to call the function?
the days are consecutive days
can I give the function a start date and repeat it with the number of items in the array?
Below is my function:
func scheduleNotification(at date: Date) {
let calendar = Calendar(identifier: .gregorian)
let components = calendar.dateComponents(in: .current, from: date)
let newComponents = DateComponents(calendar: calendar, timeZone: .current, month: components.month, day: components.day, hour: 6, minute: 30)
let trigger = UNCalendarNotificationTrigger(dateMatching: newComponents, repeats: false)
let content = UNMutableNotificationContent()
content.title = "Advent Calendar"
content.body = "Just a reminder to open your present!"
content.sound = UNNotificationSound.default()
let request = UNNotificationRequest(identifier: "textNotification", content: content, trigger: trigger)
UNUserNotificationCenter.current().removeAllPendingNotificationRequests()
UNUserNotificationCenter.current().add(request) {(error) in
if let error = error {
print("Uh oh! We had an error: \(error)")
}
}
}
Right, so after consulting with a developer #gklka I have decided to use a simple for loop that repeats 24 times ) and it passes the index to the function's day property, where I preconfigured the hour, minute, year and month like so:
func scheduleNotification(day: Int) {
var date = DateComponents()
date.year = 2016
date.month = 11
date.day = day
date.hour = 6
date.minute = 30
let trigger = UNCalendarNotificationTrigger(dateMatching: date, repeats: false)
}
and the for loop:
for index in 1...24 {
scheduleNotification(day: index)
}
Since I had everything set up int AppDelegate I call the function in didFinishLaunchingWithOptions
Update on the 1st of Dec.
So I left everything as is but no notification has occurred in the morning. 😔. I looked into my code to figure out why. There were 2 issues.
I had a line of code within my function that would delete any previous notification set up while iterating through my loop, so I had the below line of code commented out, but things still did not work as expected. UNUserNotificationCenter.current().removeAllPendingNotificationRequests()
I found that I have scheduled my notification with the same requestIdentifier, which basically left me with only 1 notification for the last day. I simply added the index at the end of my custom ID variable with string interpolation, like so: let requestId = "textNotification\(day)"
So I'm currently building a schedule app and I'm trying to create a local notification to fire on specific time on specific day of the week, every week. So the first thing I do is get the date value of the start time of the event, then I subtract 5 minutes from the start time value and then schedule the notification. Previously it was very easy just had to type:
notification.repeatInterval = CalendarUnit.WeekOfYear but now the command is deprecated in Swift 3 and yeah, so the only way I found is:
let someMinutesEarlier = Calendar.current.date(byAdding: .minute, value: -5, to: startTimePicker.date)
let contentOfNotification = UNMutableNotificationContent()
let interval = someMinutesEarlier?.timeIntervalSinceNow
contentOfNotification.title = "Event starting"
contentOfNotification.body = "Some notes"
contentOfNotification.sound = UNNotificationSound.default()
let trigger = UNTimeIntervalNotificationTrigger.init(timeInterval: interval!, repeats: true)
let request = UNNotificationRequest.init(identifier: notificationIdentifier, content: contentOfNotification, trigger: trigger)
let center = UNUserNotificationCenter.current()
center.add(request) { (error) in
print(error as Any)
}
but this only schedules the notification only once (no matter that the repeat boolean is set to true), because of the year in the someMinutesEarlier...or it's may be something else? Any idea?
As McNight mentionned, you can use UNCalendarNotificationTrigger like so:
let interval = 60 * 60 * 24 * 7 - 300 // One week minus 5 minutes.
let alarmTime = Calendar.current.date(byAdding: .second, value: interval, to: Date())!
let components = Calendar.current.dateComponents([.weekday, .hour, .minute], from: alarmTime)
let trigger = UNCalendarNotificationTrigger(dateMatching: components, repeats: true)
(I haven't tested this code, but this should get you on the right path).
More information here.
Edit: Fixed time interval calculation suggested by SwiftyCruz.
Edit 2: Updated to use a Calendar to perform the time shift as suggested by RickiG.
// Swift2.3
func setLNotification(weekDay:Int , hour:Int, min:Int, second:Int, alertBody:String, type:String, isRepeate:Bool){
let calender = NSCalendar(identifier: NSCalendarIdentifierGregorian)
let dateComp: NSDateComponents?
dateComp = calender?.components([.Year,.WeekOfMonth,.Month], fromDate: NSDate())
dateComp?.hour = hour
dateComp?.minute = min
dateComp?.second = 00
dateComp?.weekday = weekDay
dateComp!.timeZone = NSTimeZone.localTimeZone()
print(calender?.dateFromComponents(dateComp!))
let SetCustomDate = calender?.dateFromComponents(dateComp!)
print(SetCustomDate)
let notification = UILocalNotification()
if isRepeate == true{
switch type {
case "Weekly":
notification.fireDate = SetCustomDate!.dateByAddingTimeInterval(60*60*24*7)
notification.repeatInterval = NSCalendarUnit.Weekday
case "2 Weekly":
notification.fireDate = SetCustomDate!.dateByAddingTimeInterval(60*60*24*14)
notification.repeatInterval = NSCalendarUnit.Day
case "Monthly":
notification.fireDate = SetCustomDate!.dateByAddingTimeInterval(60*60*24*28)
notification.repeatInterval = NSCalendarUnit.Day
default:
break;
}
notification.soundName = UILocalNotificationDefaultSoundName
notification.repeatCalendar = calender
}
notification.alertTitle = "STATS"
notification.alertBody = "Please update your Stats detail"
notification.userInfo = ["uid":"reminder"]
print(notification)
UIApplication.sharedApplication().scheduleLocalNotification(notification)
}