I'm trying to allow the user to schedule notifications to open the app at a certain time every day. So far, I've been able to schedule the first notification by calculating the time between now and when the user selects, and scheduling a notification in X seconds. However, is there a way that I can then set that notification to repeat every day? Here's part of my code in case you're confused:
let newTime: Double = Double(totalDifference)
let notifTrigger = UNTimeIntervalNotificationTrigger(timeInterval: newTime, repeats: false)
let request = UNNotificationRequest(identifier: "openApp", content: notif, trigger: notifTrigger)
UNUserNotificationCenter.current().add(request, withCompletionHandler: { error in
if error != nil {
print(error!)
completion(false)
} else {
completion(true)
}
})
Any help is much appreciated
In your case, change this line:
let notifTrigger = UNTimeIntervalNotificationTrigger(timeInterval: newTime, repeats: false)
to
let notifTrigger = UNTimeIntervalNotificationTrigger(timeInterval: newTime, repeats: true)
From the Documentation:
UNCalendarNotificationTrigger:
Triggers a notification at the specified date and time. You use a
UNCalendarNotificationTrigger object to specify the temporal
information for the trigger condition of a notification. Calendar
triggers can fire once or they can fire multiple times.
NSDateComponents* date = [[NSDateComponents alloc] init];
date.hour = 8;
date.minute = 30;
UNCalendarNotificationTrigger* trigger = [UNCalendarNotificationTrigger
triggerWithDateMatchingComponents:date repeats:YES];
Swift:
var date = DateComponents()
date.hour = 8
date.minute = 30
let trigger = UNCalendarNotificationTrigger(dateMatching: date, repeats: true)
FOR SWIFT3
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: components.hour, minute: components.minute)
let trigger = UNCalendarNotificationTrigger(dateMatching: newComponents, repeats: true)
Related
After many researches on Stackoverflow and other websites, the only options I can find are either repeat notification on specific day of the week and specific time using:
dateComponents = DateComponents()
dateComponents.calendar = Calendar.current
dateComponents.hour = hour
dateComponents.minute = minute
dateComponents.weekday = 1 // Sunday
let trigger = UNCalendarNotificationTrigger(dateMatching: dateComponents, repeats: true)
// the above will trigger every Sunday at whatever time I set it to be.
Another option to send notification is to set time interval but not much options.
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 30, repeats: true)
I cannot find any suggestion or solution to trigger notification (number of times starting at certain time on particular day). For example: I want to trigger 5 local notification every Sunday between 8am to 5pm.
Any suggestion? Thank you in advance.
If you want to schedule multiple notifications, you need to create multiple notification triggers and register them.
something like:
// Simple extension if you have to create multiple of the same object
extension DateComponents {
static func triggerFor(hour: Int, minute: Int) -> DateComponents {
var component = DateComponents()
component.calendar = Calendar.current
component.hour = hour
component.minute = minute
component.weekday = 1
return component
}
}
// Add each trigger into an array with the correct date component
let triggers = [
UNCalendarNotificationTrigger(dateMatching: DateComponents.triggerFor(hour: 1, minute: 0), repeats: true),
UNCalendarNotificationTrigger(dateMatching: DateComponents.triggerFor(hour: 2, minute: 0), repeats: true),
UNCalendarNotificationTrigger(dateMatching: DateComponents.triggerFor(hour: 3, minute: 0), repeats: true),
UNCalendarNotificationTrigger(dateMatching: DateComponents.triggerFor(hour: 4, minute: 0), repeats: true),
UNCalendarNotificationTrigger(dateMatching: DateComponents.triggerFor(hour: 5, minute: 0), repeats: true)
]
// Iterate through the array and register the notification with the system
for trigger in triggers {
// Create the content of the notification
let content = UNMutableNotificationContent()
content.title = "My Notification Title"
content.body = "Body of Notification"
// Create the request
let uuidString = UUID().uuidString
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.
}
}
}
You would need to create your own times or dates; programming isn't smart and just going to do as you please. Coding is an exact science and needs to be treated as such.
var days = [2, 3, 4, 5, 6]
var hours = [10, 11, 12, 13, 14]
var minute = 0
for day in days {
for hour in hours {
dateComponents = DateComponents()
dateComponents.calendar = Calendar.current
dateComponents.hour = hour
dateComponents.minute = minute
dateComponents.weekday = 2
let trigger = UNCalendarNotificationTrigger(dateMatching: dateComponents, repeats: true)
}
}
This should create a series of triggers that will deliver at the top of the hour for hours of 10 11 12 13 14 on the days of 2 3 4 5 6. In human terms, assuming I have these numbers correlated correctly, it should trigger to your users every hour from 10-2 at the top of the hour on M-F.
Tbh - never used UNCalenderNotificationTrigger, but assuming it works as you state, this will create triggers for each of those times.
I've created a feature that sounds an alarm at a specific time and day of the week that you set.
func scheduleNotification() {
let center = UNUserNotificationCenter.current()
let hour = 6
let minute = 40
let weekdays = [2,3,4] // mon, tue, wed
let content = UNMutableNotificationContent()
content.title = "Fire!!"
content.body = "test.!"
content.badge = 1
content.categoryIdentifier = "alarm"
content.userInfo = ["customData": "fizzbuzz"]
content.sound = UNNotificationSound.default
for weekday in weekdays {
var dateComponents = DateComponents()
dateComponents.hour = hour
dateComponents.minute = minute
dateComponents.weekday = weekday
let trigger = UNCalendarNotificationTrigger.init(dateMatching: dateComponents, repeats: true)
let request = UNNotificationRequest(identifier: UUID().uuidString, content: content, trigger: trigger)
center.add(request)
center.getPendingNotificationRequests { (requests) in
for request in requests {
print("trigger : \(request.trigger)")
}
}
UNUserNotificationCenter.current().add(request) { (error) in
}
}
}
As you can see in the code above, the days you want to repeat are Monday, Tuesday, and Wednesday.
weekdays = [2,3,4]
After that, I wanted to create an alarm that sounds on Monday, Tuesday, and Wednesday using the for statement on the [2,3,4] array.
But the alarm didn't sound as I wanted.
I used the getPendingNotificationRequests method to print a list of scheduled alarms to the console.
trigger : Optional(<UNCalendarNotificationTrigger: 0x283242f20; dateComponents: <NSDateComponents: 0x2830567a0> {
Hour: 6
Minute: 40
Weekday: 2, repeats: YES>)
trigger : Optional(<UNCalendarNotificationTrigger: 0x283241920; dateComponents: <NSDateComponents: 0x283056900> {
Hour: 6
Minute: 40
Weekday: 2, repeats: YES>)
trigger : Optional(<UNCalendarNotificationTrigger: 0x2832416a0; dateComponents: <NSDateComponents: 0x2830556f0> {
Hour: 6
Minute: 40
Weekday: 3, repeats: YES>)
trigger : Optional(<UNCalendarNotificationTrigger: 0x283242f20; dateComponents: <NSDateComponents: 0x283056900> {
Hour: 6
Minute: 40
Weekday: 2, repeats: YES>)
trigger : Optional(<UNCalendarNotificationTrigger: 0x2832426e0; dateComponents: <NSDateComponents: 0x283054c40> {
Hour: 6
Minute: 40
Weekday: 3, repeats: YES>)
trigger : Optional(<UNCalendarNotificationTrigger: 0x2832413c0; dateComponents: <NSDateComponents: 0x283056930> {
Hour: 6
Minute: 40
Weekday: 4, repeats: YES>)
What I wanted was three triggers, and Weekday was stored one by one in the [2,3,4] array.
However, six triggers were created, and the order of Weekday was stored incorrectly.
I want to ask two questions.
If you look at the log of the above code, if you have a series of triggers with Weekday stored as 2, are they executed one by one? For example, does it sound once today if it's Monday and once next Monday?
Why is the alarm stored so wrong, and how can I solve that problem?
The reason you are getting six triggers is because, in your for loop (for weekday in weekdays), you are adding each trigger twice. Each trigger gets added once at the line center.add(request), and again at the line UNUserNotificationCenter.current().add(request) { (error) in. You could resolve this by updating your for loop to look something like this:
for weekday in weekdays {
var dateComponents = DateComponents()
dateComponents.hour = hour
dateComponents.minute = minute
dateComponents.weekday = weekday
let trigger = UNCalendarNotificationTrigger.init(dateMatching: dateComponents, repeats: true)
let request = UNNotificationRequest(identifier: UUID().uuidString, content: content, trigger: trigger)
center.current().add(request) { (error) in
if error != nil {
print(error.localizedDescription)
}
}
}
You also probably only want to print out the triggers after the for loop has completed, not within the for loop. So I would add the following code after the for loop:
func scheduleNotification() {
...
for weekday in weekdays {
...
}
//This following code was originally within your for loop, but should probably execute after the for loop instead
//The console should look a lot cleaner after doing so
center.getPendingNotificationRequests { (requests) in
for request in requests {
print("trigger : \(request.trigger)")
}
}
}
I need to push local notification each 7, 14, 28 days.
I had successfully setup to push weekly (7 days)
I am not fully understand how DateComponents works.
IE: I need to repeat notification each minute, I do Calendar.current.dateComponents([.second], from: fireDate) How does it work with repeated 14 days, 28 days.
// datetime is timestamp which I can choose: ie: May 02, 2029
let fireDate = Date(timeIntervalSince1970: Double(truncating: datetime) / 1000)
let fireDateComps = Calendar.current.dateComponents([.year, .month, .day, .hour, .minute, .second], from: fireDate)
let content = UNMutableNotificationContent()
content.title = title
content.body = note
content.sound = UNNotificationSound.default
content.categoryIdentifier = "timer.category"
var triggerDate = Calendar.current.dateComponents([.year, .month, .day, .hour, .minute, .second], from: fireDate)
var repeats = false
switch (recurring) {
case "weekly":
triggerDate = Calendar.current.dateComponents([ .weekday , .hour , .minute , .second], from: fireDate)
repeats = true
print("reminder repeat weekly")
case "every_two_weeks":
print("triggerDate 1 \(fireDate)")
let aaa = Calendar.current.date(byAdding: .day, value: 14, to: fireDate)
print("triggerDate 2 \(aaa)")
triggerDate = Calendar.current.dateComponents([.day, .hour, .minute, .second], from: aaa!)
print("triggerDate 3 \(triggerDate)")
repeats = true
print("reminder repeat every_two_weeks")
case "every_four_weeks":
triggerDate = Calendar.current.dateComponents([ .month , .hour , .minute , .second], from: fireDate)
repeats = true
print("reminder repeat every_four_weeks")
default:
triggerDate = Calendar.current.dateComponents([ .year, .month, .day , .hour , .minute , .second], from: fireDate)
repeats = false
print("No recurring")
}
let trigger = UNCalendarNotificationTrigger(dateMatching: triggerDate, repeats: repeats)
print("trigger \(trigger), firstRepeatingDate \(triggerDate)")
let request = UNNotificationRequest(identifier: id,
content: content, trigger: trigger)
self.center.add(request) {(error) in
if let error = error {
Log.nonFatal("Save notification failed \(String(describing: error))")
reject("reminder", "Save reminder notification failed", error)
}
print("Saved recurring notification")
resolve(true)
}
It's been a while since I have used these apis, but based on the documentation here is a quick example for a couple of them (the one you use and the one I am proposing):
// UNCalendarNotificationTrigger (Trigger at specific date & time)
// This example fires a notification every day at 08:30
var date = DateComponents()
date.hour = 8
date.minute = 30
let trigger = UNCalendarNotificationTrigger(dateMatching: date, repeats: true)
/* I guess date.day = 1 would fire at the 1st day of each month
whereas date.weekOfMonth = 2 would fire at the second week of each month etc
*/
What you may want instead is to fire periodically:
// UNTimeIntervalNotificationTrigger (Trigger after an amount of time has elapsed)
// This example fires a notification every 14 days (14d * 24h * 60m * 60s)
let days = 14
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: TimeInterval(days * 24 * 60 * 60), repeats: true)
I had resolved the question.
func calendarAddNotification(id: String, title: String, datetime: NSNumber, note: String, recurring: String) {
let fireDate = Date(timeIntervalSince1970: Double(truncating: datetime) / 1000)
let content = UNMutableNotificationContent()
content.title = title
content.body = note
content.sound = UNNotificationSound.default
content.categoryIdentifier = "timer.category"
// setup normal notification
let triggerDate = Calendar.current.dateComponents([.year, .month, .day, .hour, .minute, .second], from: fireDate)
let trigger = UNCalendarNotificationTrigger(dateMatching: triggerDate, repeats: false)
let request = UNNotificationRequest(identifier: id,
content: content, trigger: trigger)
self.center.add(request) {(error) in
if let error = error {
Log.nonFatal("Save notification failed \(String(describing: error))")
} else {
print("Saved notification")
}
}
// non-recurring notification, return
if (!["weekly", "every_two_weeks", "every_four_weeks"].contains(recurring)) {
print("No recurring notification")
return
}
// recurring notification
var interval = 0
switch (recurring) {
case "weekly":
interval = 7
print("reminder repeat weekly")
case "every_two_weeks":
interval = 14
print("reminder repeat every_two_weeks")
case "every_four_weeks":
interval = 28
print("reminder repeat every_four_weeks")
default:
print("No recurring")
}
// add interval day to the fireDate
let recurringDateComponent = Calendar.current.date(byAdding: .day, value: interval, to: fireDate)
let recurringTrigger = UNTimeIntervalNotificationTrigger(timeInterval: recurringDateComponent!.timeIntervalSinceNow, repeats: true)
let recurringRequest = UNNotificationRequest(identifier: "recurring_" + id,
content: content, trigger: recurringTrigger)
self.center.add(recurringRequest) { (error) in
if let error = error {
Log.nonFatal("Save recurring notification failed \(String(describing: error))")
} else {
print("Saved recurring notification")
}
}
}
I want to create a schedule for users, for now, I know how to create a specific time, but I want to create such notification for example for separate days, or only for a weekend, or for days which user which setup.
My code for hourly notification:
var notifTime = Int()
var notifMin = Int()
func test() {
let content = UNMutableNotificationContent()
content.title = "Test"
content.body = "It's test bro"
content.sound = UNNotificationSound.default()
let gregorian = Calendar(identifier: .gregorian)
let now = Date()
var components = gregorian.dateComponents([.year, .month, .day, .hour, .minute, .second], from: now)
components.hour = notifTime
components.minute = notifMin
components.second = 0
let date = gregorian.date(from: components)!
let triggerDaily = Calendar.current.dateComponents([.hour,.minute,.second,], from: date)
let trigger = UNCalendarNotificationTrigger(dateMatching: triggerDaily, repeats: true)
let request = UNNotificationRequest(identifier: "any", content: content, trigger: trigger)
UNUserNotificationCenter.current().add(request, withCompletionHandler: nil)
}
For time pick up i use date picker.
So how I can create schedule notification per days?
let startDate = Date()
let triggerDate = Calendar.current.dateComponents([.weekday,.hour,.minute], from: startDate)
Set startDate as first notification time date.
Hope it's work for you.
I'm attempting to setup a function that takes in an integer and schedules a local notification n days in the future. I'm getting an error that I can't convert type Date to DateComponents. I haven't been able to figure out how to convert it. I found a few other similar questions here and here, but I haven't been able to adapt those answers to work on Swift 3.
How can I convert Date to DateComponents? Is there a better way to schedule the notification?
Thanks in advance for the help :)
The line with the error, "Cannot convert value of type 'Date?' to expected argument type 'DateComponents'":
let trigger = UNCalendarNotificationTrigger(dateMatching: fireDateOfNotification, repeats: false)
Full function:
func scheduleNotification(day:Int) {
let date = Date()
let calendar = Calendar.current
var components = calendar.dateComponents([.day, .month, .year], from: date as Date)
let tempDate = calendar.date(from: components)
var comps = DateComponents()
//set future day variable
comps.day = day
//set date to fire alert
let fireDateOfNotification = calendar.date(byAdding: comps as DateComponents, to: tempDate!)
let trigger = UNCalendarNotificationTrigger(dateMatching: fireDateOfNotification, repeats: false) //THIS LINE CAUSES ERROR
let content = UNMutableNotificationContent()
content.title = "New Alert Title"
content.body = "Body of alert"
content.sound = UNNotificationSound.default()
let request = UNNotificationRequest(identifier: "alertNotification", content: content, trigger: trigger)
UNUserNotificationCenter.current().add(request) {(error) in
if let error = error {
print("Uh oh! We had an error: \(error)")
}
}
}
I think the error is as clear as it can be. UNCalendarNotificationTrigger is meant to be flexible, so that you can specify "fire a trigger on next Friday". All you need to is convert the next trigger day into DateComponents:
let n = 7
let nextTriggerDate = Calendar.current.date(byAdding: .day, value: n, to: Date())!
let comps = Calendar.current.dateComponents([.year, .month, .day], from: nextTriggerDate)
let trigger = UNCalendarNotificationTrigger(dateMatching: comps, repeats: false)
print(trigger.nextTriggerDate())