I am trying to schedule a Timer to fire at a specific date and time, based on what the user selects in UIDatePicker. When the Timer fires, I want to set up a repeating notification (UNTimeIntervalNotificationTrigger) every 60 seconds. The Timer seems to fire and the console shows the notification being added without error, but I never receive a notification. What am I doing wrong?
#IBAction func triggerNotification(_ sender: Any) {
if (reminderText.text!.count > 0)
{
let timer = Timer(fireAt: datePicker.date, interval: 0, target: self, selector: #selector(setUpReminder), userInfo: nil, repeats: false)
RunLoop.main.add(timer, forMode: RunLoopMode.commonModes)
self.dismiss(animated: true, completion: nil)
reminderText.text = ""
}
}
#objc func setUpReminder()
{
let content = UNMutableNotificationContent()
let identifier = reminderText.text!
content.title = "Your Reminder"
content.body = identifier
content.badge = 1
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 60.0, repeats: true)
let request = UNNotificationRequest(identifier: identifier, content: content, trigger: trigger)
UNUserNotificationCenter.current().add(request){
(error) in
if error != nil
{
print("here error in setting up notification")
print(error!)
} else
{
print("notification scheduled")
}
}
}
func sendNotification(){
let content = UNMutableNotificationContent()
content.title = "Timer"
content.body = "30 Seconds"
content.sound = UNNotificationSound.default()
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 0.001, repeats: false)
let request = UNNotificationRequest(identifier: "timer.request", content: content, trigger: trigger)
UNUserNotificationCenter.current().add(request) { (error) in
if let error = error{
print("Error posting notification:\(error.localizedDescription)")
} else{
print("notification scheduled")
}
}
}
#objc func setUpReminder()
{
UNUserNotificationCenter.current().requestAuthorization(
options: [.alert,.sound])
{(granted, error) in
self.sendNotification()
}
}
this is working code you were just assigning wrong timeinterval :)
Related
UNUserNotificationCenterDelegate functions are not called when receiving local notifications in ios (swift). Also, I am unable to receive notifications in foreground.
Here is my AppDelegate class
let notificationCenter = UNUserNotificationCenter.current()
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
DBManager.createEditableCopyOfDatabaseIfNeeded()
notificationCenter.delegate = self
let options: UNAuthorizationOptions = [.alert, .sound, .badge]
notificationCenter.requestAuthorization(options: options) {
(didAllow, error) in
if !didAllow {
print("User has declined notifications")
}
}
return true
}
}
App Delegate Extension for UNUserNotificationCenterDelegate
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void) {
completionHandler([.alert, .sound])
}
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: #escaping () -> Void) {
print(response.notification.request.content.userInfo)
completionHandler()
}
func scheduleNotification(_ body: String,_ date:Date) {
let identifier = self.convertDateInMiliseconds(date: date)
let content = UNMutableNotificationContent()
content.title = "TEST APP"
content.body = body
content.sound = UNNotificationSound.default
content.badge = 1
content.categoryIdentifier = "\(identifier)1234"
let triggerWeekly = Calendar.current.dateComponents([.weekday, .hour, .minute, .second,], from: date)
let trigger = UNCalendarNotificationTrigger(dateMatching: triggerWeekly, repeats: true)
let request = UNNotificationRequest(identifier: "\(identifier)", content: content, trigger: trigger)
UNUserNotificationCenter.current().add(request) { (error) in
if error == nil {
print("TRUE")
} else {
print("FALSE")
print(error?.localizedDescription ?? "ERROR")
}
}
let snoozeAction = UNNotificationAction(identifier: "Snooze", title: "Snooze", options: [])
let deleteAction = UNNotificationAction(identifier: "DeleteAction", title: "Delete", options: [.destructive])
let category = UNNotificationCategory(identifier: "\(identifier)1234",
actions: [snoozeAction, deleteAction],
intentIdentifiers: [],
options: [])
notificationCenter.setNotificationCategories([category])
}
func convertDateInMiliseconds(date: Date) -> Int {
let since1970 = date.timeIntervalSince1970
return Int(since1970 * 1000)
}
}
I am using iOS 14, swift 5.0 and xcode 11.5.
I am receiving notifications in background but not in foreground.
Thanks.
Try this one please
func scheduleNotification(_ body: String,_ date:Date) {
let identifier = self.convertDateInMiliseconds(date: date)
let content = UNMutableNotificationContent()
content.title = "TEST APP"
content.body = body
content.sound = UNNotificationSound.default
content.badge = 1
content.categoryIdentifier = "\(identifier)1234"
let triggerWeekly = Calendar.current.dateComponents([.weekday, .hour, .minute, .second,], from: date)
let trigger = UNCalendarNotificationTrigger(dateMatching: triggerWeekly, repeats: true)
let center = UNUserNotificationCenter.current()
center.delegate = self
let request = UNNotificationRequest(identifier: "\(identifier)", content: content, trigger: trigger)
UNUserNotificationCenter.current().add(request) { (error) in
if error == nil {
print("TRUE")
} else {
print("FALSE")
print(error?.localizedDescription ?? "ERROR")
}
}
let snoozeAction = UNNotificationAction(identifier: "Snooze", title: "Snooze", options: [])
let deleteAction = UNNotificationAction(identifier: "DeleteAction", title: "Delete", options: [.destructive])
let category = UNNotificationCategory(identifier: "\(identifier)1234",
actions: [snoozeAction, deleteAction],
intentIdentifiers: [],
options: [])
notificationCenter.setNotificationCategories([category])
}
Unless I explicitly select a row, the UIPickerView crashes and I get the error
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'time interval must be greater than 0'
I understand that it crashes because it's not selecting any one of the rows, and the default value for Time Interval is 0.
So how can I get the PickerView to select the first row without me having to explicitly select it myself?
Here is the relevant code:
var timerDisplayed = 0
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
timerDisplayed = Int(timeSelect[row])!
}
#objc func timeClock(){
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound]) { (didAllow, error) in }
let content = UNMutableNotificationContent()
content.title = "Time is up!"
content.badge = 1
content.sound = UNNotificationSound.init(named: UNNotificationSoundName(rawValue: "note1.wav"))
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: TimeInterval(timerDisplayed), repeats: false)
let request = UNNotificationRequest(identifier: "timerDone", content: content, trigger: trigger)
UNUserNotificationCenter.current().add(request, withCompletionHandler: nil)
self.timerTextField.text = (" \(String(self.timerDisplayed))")
dismissKeyboard()
DispatchQueue.main.async {
self.timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(self.Action), userInfo: nil, repeats: true)
}
}
#objc func Action(){
if timerDisplayed != 0 {
DispatchQueue.main.async {
self.timerDisplayed -= 1
self.timerTextField.text = (" \(String(self.timerDisplayed))")
}
}
else {
self.timer.invalidate()
self.timerTextField.text = nil
self.timerTextField.placeholder = " Timer"
}
}
Maybe you could just play with your timeClock() method, to have this in the first line:
let timerDisplayed = self.timerDisplayed > 0 ? timerDisplayed : Int(timeSelect[0])!
So it could look like this:
#objc func timeClock(){
let timerDisplayed = self.timerDisplayed > 0 ? timerDisplayed : Int(timeSelect[0])!
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound]) { (didAllow, error) in }
let content = UNMutableNotificationContent()
content.title = "Time is up!"
content.badge = 1
content.sound = UNNotificationSound.init(named: UNNotificationSoundName(rawValue: "note1.wav"))
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: TimeInterval(timerDisplayed), repeats: false)
let request = UNNotificationRequest(identifier: "timerDone", content: content, trigger: trigger)
UNUserNotificationCenter.current().add(request, withCompletionHandler: nil)
self.timerTextField.text = (" \(String(self.timerDisplayed))")
dismissKeyboard()
DispatchQueue.main.async {
self.timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(self.Action), userInfo: nil, repeats: true)
}
}
Or you can just put this in viewDidLoad to have the first row auto selected:
let defaultFirstRow = pickerView.selectedRow(inComponent: 0);
pickerView(pickerView, didSelectRow: defaultFirstRow, inComponent:0)
So I had an interacitve push notification but it suddenly stopped working,
this is my code:
func pushNotification(){
let content = UNMutableNotificationContent()
let answer1 = UNNotificationAction(identifier: "answer1", title: "thank you!", options: UNNotificationActionOptions.foreground)
let category = UNNotificationCategory(identifier: "myCategory", actions: [answer1, answer2], intentIdentifiers: [], options: [])
UNUserNotificationCenter.current().setNotificationCategories([category])
content.sound = UNNotificationSound.default()
//Created notification
content.body = "how are you?"
content.categoryIdentifier = "myCategory"
content.badge = 1
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 10, repeats: false)
let request = UNNotificationRequest(identifier: "timerDone", content: content, trigger: trigger)
UNUserNotificationCenter.current().add(request, withCompletionHandler: nil)
}
#objc(userNotificationCenter:didReceiveNotificationResponse:withCompletionHandler:) func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: #escaping () -> Void)
{
if response.actionIdentifier == "answer1"
{
print("ok")
performSegue(withIdentifier: "FastResult", sender: self)
}
completionHandler()
}
when I run the app I get the notification but I doen't recive the output: "ok" and there is no segue.
response.actionIdentifier == "answer1" only will be true when you tap on "thank you!" option in the notification. It wont be true if you just tap the notification. please check
How can I run for example local notifications?
In UNUserNotificationCenter there is not repeat feature.
Maybe using NSTimer or something like this?
Why my code does not work as I expected
let hours: [Int] = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24]
for hour in hours {
for minute in stride(from: 0, to: 60, by: 5){
let content = UNMutableNotificationContent()
content.title = "Title"
content.body = "Body"
var dateComponents = DateComponents()
dateComponents.hour = hour
dateComponents.minute = minute
let trigger = UNCalendarNotificationTrigger(dateMatching: dateComponents, repeats: true)
let request = UNNotificationRequest(identifier: "timerDone", content: content, trigger: trigger)
let center = UNUserNotificationCenter.current()
center.add(request) { (error : Error?) in
if let theError = error {
print(theError.localizedDescription)
}
}
}
}
There is a repeat feature.
From Apple's documentation:
let content = UNMutableNotificationContent()
content.title = NSString.localizedUserNotificationString(forKey:
"Hello!", arguments: nil)
content.body = NSString.localizedUserNotificationString(forKey:
"Hello_message_body", arguments: nil)
// Deliver the notification in five seconds and repeat it
content.sound = UNNotificationSound.default()
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 60,
repeats: true)
// Schedule the notification.
let request = UNNotificationRequest(identifier: "60_seconds", content: content, trigger: trigger)
let center = UNUserNotificationCenter.current()
center.add(request, withCompletionHandler: nil)
Edit:
As also written in the documentation, you certainly have to have user permissions to post notifications:
let center = UNUserNotificationCenter.current()
center.requestAuthorization(options: [.alert, .sound]) { (granted, error) in
// Enable or disable features based on authorization
}
Result:
Notification is posted every minute:
I need your help for a project.
I have 3 variables, one for the day , another for the month and last for the year. Like that :
var year = 2017
var month = 06
var day = 19
I want to send a notification even if the app is close when we are at the date of these variable, but i'm not really good with Calendar and Date. I just made this app for the moment.
let myNotification = Notification.Name(rawValue:"MyNotification")
override func viewDidLoad() {
super.viewDidLoad()
let nc = NotificationCenter.default
nc.addObserver(forName:myNotification, object:nil, queue:nil, using:catchNotification)
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
let nc = NotificationCenter.default
nc.post(name:myNotification,
object: nil,
userInfo:["message":"Hello there!", "date":Date()])
}
func catchNotification(notification:Notification) -> Void {
print("Catch notification")
guard let userInfo = notification.userInfo,
let message = userInfo["message"] as? String,
let date = userInfo["date"] as? Date else {
print("No userInfo found in notification")
return
}
let alert = UIAlertController(title: "Notification!",
message:"\(message) received at \(date)",
preferredStyle: UIAlertControllerStyle.alert)
alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: nil))
self.present(alert, animated: true, completion: nil)
}
Thank you in advance
You need to set up a local notification and use a UNCalendarNotificationTrigger to fire it at a specific date.
let dateComponents = DateComponents(year: year, month: month, day: day)
let yourFireDate = Calendar.current.date(from: dateComponents)
let content = UNMutableNotificationContent()
content.title = NSString.localizedUserNotificationString(forKey:
"Your notification title", arguments: nil)
content.body = NSString.localizedUserNotificationString(forKey: "Your notification body", arguments: nil)
content.categoryIdentifier = "Your notification category"
content.sound = UNNotificationSound.default()
content.badge = 1
let dateComponents = Calendar.current.dateComponents(Set(arrayLiteral: Calendar.Component.year, Calendar.Component.month, Calendar.Component.day), from: yourFireDate)
let trigger = UNCalendarNotificationTrigger(dateMatching: dateComponents, repeats: false)
let request = UNNotificationRequest(identifier: "Your notification identifier", content: content, trigger: trigger)
UNUserNotificationCenter.current().add(request, withCompletionHandler: { error in
if let error = error {
//handle error
} else {
//notification set up successfully
}
}
In swift 3 - 4 use this.
func scheduleLocal() {
let dateComponents = DateComponents(year: 2019, month: 1, day: 17, hour: 10, minute: 20)
let yourFireDate = Calendar.current.date(from: dateComponents)
let notification = UILocalNotification()
notification.fireDate = yourFireDate
notification.alertBody = "Hey you! Yeah you! Swipe to unlock!"
notification.alertAction = "be awesome!"
notification.soundName = UILocalNotificationDefaultSoundName
notification.userInfo = ["CustomField1": "w00t"]
UIApplication.shared.scheduleLocalNotification(notification)
}