Schedule local notifications on user selected week days in iOS - ios

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!

Related

Fire Notification Daily but After a certain date

I Know, This may be [duplicate question][1]. I tried so many solutions but no one solution meet my expectation. Here is my scenario.
Notification StartDate: 26-July-2022
Today's Date: 23-July-2022
I want to set a repeat Local notification from a certain start date.
Here is my Code :
func scheduleLocalNotification(startDate: Date) {
var calendar = Calendar.current
calendar.timeZone = TimeZone.current
let content = UNMutableNotificationContent()
content.title = "REMINDER For Yoga"
content.body = "Hi! Get ready for Daily Yoga Class."
content.categoryIdentifier = "Yoga_872"
let components = calendar.dateComponents([.hour, .minute], from: startDate)
let trigger = UNCalendarNotificationTrigger(dateMatching: components, repeats: true)
let identifier = "Yoga_Class(222)"
let notificationRequest = UNNotificationRequest(identifier: identifier, content: content, trigger: trigger)
// Add Request to User Notification Center
UNUserNotificationCenter.current().add(notificationRequest) { (error) in
if let error = error {
print("Add Notification Request Error: (\(error), \(error.localizedDescription))")
}
}
}
This code is firing notification from today not from Start date (26-July-2022).
[1]: Set repeat Local notification from date

Schedule future UNUserNotificationCenter with condition and limits (iOS)

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.

Repeat UNNotifications every day and every half hour

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.

Repeating local notifications for specific days of week (Swift 3 IOS 10)

I am trying to schedule local notifications for specific days of week (e.g. Monday, Wednesday and etc) and then repeat them weekly.
This is how the screen for setting notifications looks:
User can select time for the notification and repeating days.
My method for scheduling single non repeating notification looks like this:
static func scheduleNotification(reminder: Reminder) {
// Setup notification content.
let content = UNMutableNotificationContent()
//content.title = NSString.localizedUserNotificationString(forKey: "Reminder", arguments: nil)
content.body = NSString.localizedUserNotificationString(forKey: reminder.reminderMessage, arguments: nil)
content.sound = UNNotificationSound.default()
// Configure the triger for specified time.
//
let dateComponentes = reminder.dateComponents
// TODO: Configure repeating alarm
// For the testing purposes we will not repeat the reminder
let trigger = UNCalendarNotificationTrigger(dateMatching: dateComponentes, repeats: false)
// Create the request object.
let request = UNNotificationRequest(identifier: "\(reminder.reminderId)", content: content, trigger: trigger)
// Schedule the request.
let notificationCenter = UNUserNotificationCenter.current()
notificationCenter.add(request) { (error: Error?) in
if let theError = error {
print(theError.localizedDescription)
}
}
}
The date components are extracted from UIDatePicker widget and stored in reminder class:
let date = reminderTimeDatePicker.date.addingTimeInterval(60 * 60 * 24 * 7)
let components = Calendar.current.dateComponents([.weekday, .hour, .minute], from: date)
...
reminder.dateComponents = components
I have an array selectedDays[Int] (as a property of reminder class) to hold info on days of week on which the notification should fire.
How can I schedule notification on specific day of week and how to repeat it weekly?
Even a single comment will be helpful, and thank you in advance.
You can use below function to get Date from selected picker value:
//Create Date from picker selected value.
func createDate(weekday: Int, hour: Int, minute: Int, year: Int)->Date{
var components = DateComponents()
components.hour = hour
components.minute = minute
components.year = year
components.weekday = weekday // sunday = 1 ... saturday = 7
components.weekdayOrdinal = 10
components.timeZone = .current
let calendar = Calendar(identifier: .gregorian)
return calendar.date(from: components)!
}
//Schedule Notification with weekly bases.
func scheduleNotification(at date: Date, body: String, titles:String) {
let triggerWeekly = Calendar.current.dateComponents([.weekday,.hour,.minute,.second,], from: date)
let trigger = UNCalendarNotificationTrigger(dateMatching: triggerWeekly, repeats: true)
let content = UNMutableNotificationContent()
content.title = titles
content.body = body
content.sound = UNNotificationSound.default()
content.categoryIdentifier = "todoList"
let request = UNNotificationRequest(identifier: "textNotification", 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)")
}
}
}
After getting a value from picker pass picker hour, minute and year with selected week day as (Sunday = 1, Monday = 2, Tuesday = 3, Wednesday = 4, thursday = 5, Friday = 6, Saturday = 7) to function func createDate(weekday: Int, hour: Int, minute: Int, year: Int) to get notification fire date on weekly bases, and after getting date call function func scheduleNotification(at date: Date, body: String, titles:String) for schedule a notification.
let content = UNMutableNotificationContent()
content.title = NSString.localizedUserNotificationString(forKey: "Wake up!", arguments: nil)
content.body = NSString.localizedUserNotificationString(forKey: "Rise and shine! It's morning time!",
arguments: nil)
content.categoryIdentifier = "TIMER_EXPIRED"
let weekdaySet = [6,5]
for i in weekdaySet {
var dateInfo = DateComponents()
dateInfo.hour = 16
dateInfo.minute = 44
dateInfo.weekday = i
dateInfo.timeZone = .current
let trigger = UNCalendarNotificationTrigger(dateMatching: dateInfo, repeats: true)
let request = UNNotificationRequest(identifier: UUID().uuidString, content: content, trigger: trigger)
center.add(request) { (error : Error?) in
if let theError = error {
print(theError.localizedDescription)
}
}
}

Scheduling notification with Swift 3 for an array of dates

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

Resources