I am trying to create a notification based on date and time specified by a user for an application I am working on. I am able to save user's date and retrieve. I now want a notification to pop up when the user's specified date has arrived just like an reminder thing. I can create a notification with with hard coded values but now retriving from the Real database to pass into the trigger value is what I am unable to do. my codes are specified below
func notifcation() -> Void {
let calendar = Calendar.current
let components = DateComponents(year: 2018, month: 09, day: 08, hour: 18, minute: 55) // Set the date here when you want Notification
let date = calendar.date(from: components)
let comp2 = calendar.dateComponents([.year,.month,.day,.hour,.minute], from: date!)
let trigger = UNCalendarNotificationTrigger(dateMatching: comp2, repeats: true)
let content = UNMutableNotificationContent()
content.title = "Don't forget"
content.body = "Buy some milk"
content.sound = UNNotificationSound.default()
let identifier = "UYLLocalNotification"
let request = UNNotificationRequest(identifier: identifier,
content: content, trigger: trigger)
center.add(request, withCompletionHandler: { (error) in
if let error = error {
// Something went wrong
print(error as Any)
}
})
}
then I call notification() in my viewDidLoad
Model
class ListModel: Object {
#objc dynamic var createdDate: Date?
#objc dynamic var remiderDate: Date?
}
based on Sh answer
My function
func getDataFromDB() -> Results<ListModel>? {
let todoListArray: Results<ListModel> = database.objects(ListModel.self)
return todoListArray
}
my viewdidLoad was now
TodoListFunctions.instance.getDataFromDB()?.forEach({ (list) in
notifcation(list.remiderDate)
})
in my AppDelegate for Permission
let center = UNUserNotificationCenter.current()
let options: UNAuthorizationOptions = [.alert, .sound]
center.requestAuthorization(options: options) {
(granted, error) in
if !granted {
print("Something went wrong")
}
}
further codes would be supplied on request
You can try
let allList = self.database.objects(ListModel.self)
allList.forEach{ notifcation($0.remiderDate) }
//
func notifcation(_ reminder:Date?) -> Void {
guard let date = reminder else { return }
let comp2 = calendar.dateComponents([.year,.month,.day,.hour,.minute], from: date)
let trigger = UNCalendarNotificationTrigger(dateMatching: comp2, repeats: true)
let content = UNMutableNotificationContent()
content.title = "Don't forget"
content.body = "Buy some milk"
content.sound = UNNotificationSound.default()
let identifier = "\(date)" // identider should be different for each one
let request = UNNotificationRequest(identifier: identifier,
content: content, trigger: trigger)
center.add(request, withCompletionHandler: { (error) in
if let error = error {
// Something went wrong
print(error as Any)
}
})
}
//
Set the delegate inside AppDelegte
UNUserNotificationCenter.current().delegate = self
and notice the print from
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("notification received")
}
Related
I added this code to my first ViewController
// Step-1 Ask permission from User
let center = UNUserNotificationCenter.current()
center.requestAuthorization(options: [.badge,.sound,.alert]) { granted, error in
if error == nil {
print("User permission is granted : \(granted)")
}
}
// Step-2 Create the notification content
let content = UNMutableNotificationContent()
content.title = "Hello"
content.body = "Welcome"
// Step-3 Create the notification trigger
let date = Date().addingTimeInterval(1)
let dateComponent = Calendar.current.dateComponents([.year,.month,.day,.hour,.minute,.second], from: date)
let trigger = UNCalendarNotificationTrigger(dateMatching: dateComponent, repeats: false)
// Step-4 Create a request
let uuid = UUID().uuidString
let request = UNNotificationRequest(identifier: uuid, content: content, trigger: trigger)
// Step-5 Register with Notification Center
center.add(request) { error in
but 5 seconds pass without any notification shown. What is wrong? Could somebody show me how to fix it??
The notification comes but when the app is foreground it won't show until you implement UNUserNotificationCenterDelegate method
UNUserNotificationCenter.current().delegate = self
func userNotificationCenter(_ center: UNUserNotificationCenter,
willPresent notification: UNNotification,
withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void) {
completionHandler([.sound,.alert])
}
Also set
let date = Date().addingTimeInterval(5)
to give it some time until app hits so you can test it after clicking home button
import UIKit
class ViewController: UIViewController , UNUserNotificationCenterDelegate {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
let center = UNUserNotificationCenter.current()
center.delegate = self
center.requestAuthorization(options: [.badge,.sound,.alert]) { granted, error in
if error == nil {
print("User permission is granted : \(granted)")
}
}
// Step-2 Create the notification content
let content = UNMutableNotificationContent()
content.title = "Hello"
content.body = "Welcome"
// Step-3 Create the notification trigger
let date = Date().addingTimeInterval(5)
let dateComponent = Calendar.current.dateComponents([.year,.month,.day,.hour,.minute,.second], from: date)
let trigger = UNCalendarNotificationTrigger(dateMatching: dateComponent, repeats: false)
// Step-4 Create a request
let uuid = UUID().uuidString
let request = UNNotificationRequest(identifier: uuid, content: content, trigger: trigger)
// Step-5 Register with Notification Center
center.add(request) { error in
}
}
func userNotificationCenter(_ center: UNUserNotificationCenter,
willPresent notification: UNNotification,
withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void) {
completionHandler([.sound,.alert])
}
}
I'm trying to implement local notifications within my app. The idea is that the user is sent a notification every day at 9:00 a.m. with a different quote, but I encountered a bug where the same content of the notification is always shown, i.e. the same quote is repeated endlessly. How could I fix it? This is the code I'm using, and I tried to use a UUID for every notification that is sent, but it didn't bring improvements.
let notificationCenter = UNUserNotificationCenter.current()
let options: UNAuthorizationOptions = [.alert, .sound]
notificationCenter.requestAuthorization(options: options) {
(didAllow, error) in
if !didAllow {
print("User has declined notifications")
}
}
notificationCenter.getNotificationSettings { (settings) in
if settings.authorizationStatus != .authorized {
print("Notifications not allowed")
}
}
let randomArrayNotificationQuote = Int(arc4random_uniform(UInt32(myQuotes.count)))
let randomArrayNotificationTitle = Int(arc4random_uniform(UInt32(myTitle.count)))
let content = UNMutableNotificationContent()
content.title = "\(myTitle[randomArrayNotificationTitle])"
content.body = "\(myQuotes[randomArrayNotificationQuote])"
content.sound = UNNotificationSound.default
content.categoryIdentifier = "com.giovannifilippini.philo"
// Deliver the notification
var dateComponents = DateComponents()
dateComponents.hour = 9
dateComponents.minute = 00
let trigger = UNCalendarNotificationTrigger(dateMatching: dateComponents, repeats: true)
let uuid = UUID().uuidString
let request = UNNotificationRequest.init(identifier: uuid, content: content, trigger: trigger)
notificationCenter.add(request) { (error) in
if error != nil {
print("add NotificationRequest succeeded!")
notificationCenter.removePendingNotificationRequests(withIdentifiers: [uuid])
}
}
The issue here is the trigger has the repeats set to true
let trigger = UNCalendarNotificationTrigger(dateMatching: dateComponents, repeats: true)
You would need to set it to false and re run this method every time you want to schedule different notification (different content)
In order to receive the Notification while the app is in the foreground you need to implement the willPresent method from the UNUserNotificationCenterDelegate
Here is a simple example:
class ViewController: UIViewController {
private let userNotificaionCenter = UNUserNotificationCenter.current()
override func viewDidLoad() {
super.viewDidLoad()
// 1. Assign the delegate
userNotificaionCenter.delegate = self
scheduleNotification()
}
func scheduleNotification() {
// Same notification logic that you have
}
}
// 2. Implement the UNUserNotificationCenterDelegate
extension ViewController: UNUserNotificationCenterDelegate {
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void) {
// This will allow the app to receive alerts and sound while in the foreground
completionHandler([.alert, .sound])
}
}
In my app I want to give a notification for an event when the user first enters the app. I have the notifications set up in another viewController handling the calendar that holds the events:
//setup calendar notifications
func createNotification(){
let content = UNMutableNotificationContent()
content.title = "Event"
content.subtitle = eventNameArray[0]
content.body = descriptionsArray[0]
content.sound = UNNotificationSound.default()
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 3.0, repeats: false)
let request = UNNotificationRequest(identifier: "notification", content: content, trigger: trigger)
UNUserNotificationCenter.current().add(request){
(error) in
print(error as Any)
}
}
This notification only triggers in when the user goes to the calendar page.
How do I display this notification when the user boots up the app? Do I need to make changes to the AppDelegate?
EDIT: Following a this tutorial (https://www.youtube.com/watch?v=cx2B8P84tS4) I implemented a new class to push the notifications:
import UIKit
import UserNotifications
class NotificationPublisher: NSObject {
func sendNotification(title: String,
subtitle: String,
body: String,
badge: Int?,
delayInterval: Int?){
let notificationContent = UNMutableNotificationContent()
notificationContent.title = title
notificationContent.subtitle = subtitle
notificationContent.body = body
var delayTimeTrigger: UNTimeIntervalNotificationTrigger?
if let delayInterval = delayInterval {
delayTimeTrigger = UNTimeIntervalNotificationTrigger(timeInterval: TimeInterval(delayInterval), repeats: false)
}
if let badge = badge {
var currentBadgeCount = UIApplication.shared.applicationIconBadgeNumber
currentBadgeCount += badge
notificationContent.badge = NSNumber(integerLiteral: currentBadgeCount)
}
notificationContent.sound = UNNotificationSound.default()
UNUserNotificationCenter.current().delegate = self
let request = UNNotificationRequest(identifier: "TestLocalNotification", content: notificationContent, trigger: delayTimeTrigger)
UNUserNotificationCenter.current().add(request) {
error in
if let error = error {
print(error.localizedDescription)
}
}
}
}
extension NotificationPublisher: UNUserNotificationCenterDelegate {
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void) {
completionHandler([.alert, .sound, .badge])
}
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: #escaping () -> Void) {
let identifier = response.actionIdentifier
switch identifier {
case UNNotificationDismissActionIdentifier:
print("Notification dismissed")
completionHandler()
case UNNotificationDefaultActionIdentifier:
print("User opened app from notification ")
default:
print("Default case was called")
completionHandler()
}
}
}
Then inside the viewController of the startup page I did this:
class ViewController: UIViewController{
private let notificationPublisher = NotificationPublisher()
private let calendarEvents = CalendarController()
override func viewDidLoad() {
super.viewDidLoad()
print("Events to show in notification: ", calendarEvents.descriptionsArray)
notificationPublisher.sendNotification(title: "Hey", subtitle: "Testing", body: "Is this working?", badge: 1, delayInterval: nil )
}
}
The app shows the notification on startup but I cannot display anything inside the calendarEvents.descriptionsArray as it is empty. How do I make it so the array is filled with data from a server so that the notification can display the event?
You can do simply the same in AppDelegate class on method applicationDidFinishLaunchingWithOptions
you may want to save a flag to NSUSerDefaults to indicate whether it is the very first launch of the app or not and act accordingly (display local notification)
I'm learning the new notification system but I'm having trouble with actions. The notification works, but I do't get an action with it. I'm following a tutorial on https://www.appcoda.com/ios10-user-notifications-guide/ but I don't seem to get actions to appear with notification.
As you can see the commented out part in func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey : Any]? = nil)is where I cannot seem to get where it goes, can anyone see where I'm mistaking?
import UIKit
import UserNotifications
#UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func scheduleNotification(at date: Date) {
UNUserNotificationCenter.current().delegate = self
//compone a new Date components because components directly from Date don't work
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)
//create the trigger with above new date components, with no repetitions
let trigger = UNCalendarNotificationTrigger(dateMatching: newComponents, repeats: false)
//create the content for the notification
let content = UNMutableNotificationContent()
content.title = "Tutorial Reminder"
content.body = "Just a reminder to read your tutorial over at appcoda.com!"
content.sound = UNNotificationSound.default()
// notification action category
//add an image to notification
//convert logo to url
if let path = Bundle.main.path(forResource: "logo", ofType: "png") {
let url = URL(fileURLWithPath: path)
do { // because UNNotificationAttachment is mark as throwing we need an attach block for handling errors
let attachment = try UNNotificationAttachment(identifier: "logo", url: url, options: nil)
content.attachments = [attachment]
content.categoryIdentifier = "myCategory"
} catch {
print("The attachment was not loaded.")
}
}
//create the request for notification with desired parameters
let request = UNNotificationRequest(identifier: "textNotification", content: content, trigger: trigger)
//add the request to notification center after removing all notifications
UNUserNotificationCenter.current().removeAllPendingNotificationRequests()
UNUserNotificationCenter.current().add(request) {(error) in
if let error = error {
print("Uh oh! We had an error: \(error)")
}
}
}
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey : Any]? = nil) -> Bool {
// let action = UNNotificationAction(identifier: "remindLater", title: "Remind me later", options: [])
// let category = UNNotificationCategory(identifier: "myCategory", actions: [action], intentIdentifiers: [], options: [])
// UNUserNotificationCenter.current().setNotificationCategories([category])
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound]) {(accepted, error) in
if !accepted {
// print("Notification access denied.")
// let action = UNNotificationAction(identifier: "remindLater", title: "Remind me later", options: [])
// let category = UNNotificationCategory(identifier: "myCategory", actions: [action], intentIdentifiers: [], options: [])
// UNUserNotificationCenter.current().setNotificationCategories([category])
}
}
let action = UNNotificationAction(identifier: "remindLater", title: "Remind me later", options: [])
let category = UNNotificationCategory(identifier: "myCategory", actions: [action], intentIdentifiers: [], options: [])
UNUserNotificationCenter.current().setNotificationCategories([category])
return true
}
}
extension AppDelegate: UNUserNotificationCenterDelegate {
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: #escaping () -> Void) {
if response.actionIdentifier == "remindLater" {
let newDate = Date(timeInterval: 5, since: Date())
scheduleNotification(at: newDate)
}
// UNUserNotificationCenter.current().delegate = self
}
}
EDIT:
after #VIP-DEV answer I changed the code, to add the reminder in it's own action, into:
import UIKit
import UserNotifications
#UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
UNUserNotificationCenter.current().delegate = self as? UNUserNotificationCenterDelegate
configureCategory()
triggerNotification(at: Date())
requestAuth()
return true
}
private let category = "Notification.Category.Read"
private let readActionIdentifier = "Read"
private let waitActionIdentifier = "Wait"
private func requestAuth() {
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) { (success, error) in
if let error = error {
print("Request Authorization Failed (\(error), \(error.localizedDescription))")
}
}
}
func triggerNotification(at date: Date) {
// Create Notification Content
let notificationContent = UNMutableNotificationContent()
//compone a new Date components because components directly from Date don't work
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)
//create the trigger with above new date components, with no repetitions
// Configure Notification Content
notificationContent.title = "Hello"
notificationContent.body = "Kindly read this message."
// Set Category Identifier
notificationContent.categoryIdentifier = category
// Add Trigger
// let notificationTrigger = UNTimeIntervalNotificationTrigger(timeInterval: 10.0, repeats: false)
let trigger = UNCalendarNotificationTrigger(dateMatching: newComponents, repeats: false)
// // Create Notification Request
let notificationRequest = UNNotificationRequest(identifier: "test_local_notification", content: notificationContent, trigger: trigger)
//
// Add Request to User Notification Center
UNUserNotificationCenter.current().add(notificationRequest) { (error) in
if let error = error {
print("Unable to Add Notification Request (\(error), \(error.localizedDescription))")
}
}
}
private func configureCategory() {
// Define Actions
let read = UNNotificationAction(identifier: readActionIdentifier, title: "Read", options: [])
let wait = UNNotificationAction(identifier: waitActionIdentifier, title : "Wait", options: [])
// Define Category
let readCategory = UNNotificationCategory(identifier: category, actions: [read, wait], intentIdentifiers: [], options: [])
// Register Category
UNUserNotificationCenter.current().setNotificationCategories([readCategory])
}
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void) {
completionHandler([.alert])
}
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: #escaping () -> Void) {
switch response.actionIdentifier {
case readActionIdentifier:
print("Read tapped")
case waitActionIdentifier:
let NewDate = Date(timeInterval: 20, since: Date())
triggerNotification(at: NewDate)
print("Wait tapped")
default:
print("Other Action")
}
completionHandler()
}
}
and
class ViewController: UIViewController {
#IBAction func datePickerDidSelectNewDate(_ sender: UIDatePicker) {
let selectedDate = sender.date
let delegate = UIApplication.shared.delegate as? AppDelegate
// delegate?.scheduleNotification(at: selectedDate)
delegate?.triggerNotification(at: selectedDate)
}
}
Now I don't get to set new notification when tap on wait button. where do I have to set let NewDate = Date(timeInterval: 20, since: Date())
triggerNotification(at: NewDate)? I thought it went in case waitActionIdentifier but I don't even get the print to console.
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
UNUserNotificationCenter.current().delegate = self
configureCategory()
triggerNotification()
requestAuth()
return true
}
private let category = "Notification.Category.Read"
private let actionIdentifier = "Read"
private func requestAuth() {
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) { (success, error) in
if let error = error {
print("Request Authorization Failed (\(error), \(error.localizedDescription))")
}
}
}
private func triggerNotification() {
// Create Notification Content
let notificationContent = UNMutableNotificationContent()
// Configure Notification Content
notificationContent.title = "Hello"
notificationContent.body = "Kindly read this message."
// Set Category Identifier
notificationContent.categoryIdentifier = category
// Add Trigger
let notificationTrigger = UNTimeIntervalNotificationTrigger(timeInterval: 3.0, repeats: false)
// Create Notification Request
let notificationRequest = UNNotificationRequest(identifier: "test_local_notification", content: notificationContent, trigger: notificationTrigger)
// Add Request to User Notification Center
UNUserNotificationCenter.current().add(notificationRequest) { (error) in
if let error = error {
print("Unable to Add Notification Request (\(error), \(error.localizedDescription))")
}
}
}
private func configureCategory() {
// Define Actions
let read = UNNotificationAction(identifier: actionIdentifier, title: "Read", options: [])
// Define Category
let readCategory = UNNotificationCategory(identifier: category, actions: [read], intentIdentifiers: [], options: [])
// Register Category
UNUserNotificationCenter.current().setNotificationCategories([readCategory])
}
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void) {
completionHandler([.alert])
}
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: #escaping () -> Void) {
switch response.actionIdentifier {
case actionIdentifier:
print("Read tapped")
default:
print("Other Action")
}
completionHandler()
}
The declaration of the category identifier was declared as private.
Now the Notification actions work as expected.
Thanks to VIP-DEV's answer I could find how to correct my code.
I am trying to send a notification on a button click. This is the code in my viewController:
#IBAction func getNotificationButtonPressed(_ sender: Any) {
let content = UNMutableNotificationContent()
content.title = "Title"
content.body = "Body"
content.categoryIdentifier = "ident"
content.sound = UNNotificationSound.default()
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 0.1, repeats: false)
let request = UNNotificationRequest(identifier: "ident", content: content, trigger: trigger)
let center = UNUserNotificationCenter.current()
center.add(request) { (error : Error?) in
if let theError = error {
print(theError.localizedDescription)
} else {
print ("success")
}
}
}
also in AppDelegate I have requested permission to use Notifications:
let center = UNUserNotificationCenter.current()
center.requestAuthorization(options:[.badge, .alert, .sound]) { (granted, error) in
// Enable or disable features based on authorization.
}
application.registerForRemoteNotifications()
P.S. I have imported
import UserNotifications
in both AppDelegate and the custom ViewController.
When you create notification at that check
if #available(iOS 10.0, *) {
let content = UNMutableNotificationContent()
content.title = "Intro to Notifications"
content.subtitle = "Lets code,Talk is cheap"
content.body = "Sample code from WWDC"
content.sound = UNNotificationSound.default()
// Deliver the notification in five seconds.
let trigger = UNTimeIntervalNotificationTrigger.init(timeInterval: 5.0, repeats: false)
let request = UNNotificationRequest(identifier:requestIdentifier, content: content, trigger: trigger)
UNUserNotificationCenter.current().delegate = self
UNUserNotificationCenter.current().add(request){(error) in
if (error != nil){
print(error?.localizedDescription)
}
}
}
Implement this delegates method UNUserNotification for Notification being triggered.
#available(iOS 10.0, *)
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: #escaping () -> Void) {
print("Tapped in notification")
}
//This is key callback to present notification while the app is in foreground
#available(iOS 10.0, *)
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void) {
print("Notification being triggered")
//You can either present alert ,sound or increase badge while the app is in foreground too with ios 10
//to distinguish between notifications
if notification.request.identifier == requestIdentifier{
completionHandler( [.alert,.sound,.badge])
}
}
Happy coding.