Sending local notifications in SWIFT - ios

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])
}
}

Related

Local Notification content going into a loop in iOS

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])
}
}

userNotificationCenter didReceive is not being called when tapping a notification

I have set the following local notification:
let content = UNMutableNotificationContent()
content.title = "Some Title"
content.body = "Some text"
content.sound = UNNotificationSound.default
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 20, repeats: false)
let request = UNNotificationRequest(identifier: "OneDay", content: content, trigger: trigger)
notificationCenter.add(request)
And I have added the following to AppDelegate
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: #escaping () -> Void) {
print("Notification Tapped")
if response.notification.request.identifier == "OneDay" {
print("OneDay Notification Tapped")
}
completionHandler()
}
notificationCenter has been set as:
let notificationCenter = UNUserNotificationCenter.current()
However, none of the above print statements work. The notification is presented, I tap on it, the app is brought to the foreground but nothing is printed to the console.
Am I missing anything here? I've tested in both the simulator and a device. Same result.
I'm working with XCode 11.5, deploying for 12.0.
I'm not sure what is going as I'd have to see the complete code, so I just made a minimal example for you to understand. It also works perfectly fine in the Simulator.
Please feel free to let me know if you have any questions!
First make sure you're asking for the user permission before setting your delegate or scheduling any local notifications, otherwise your notifications will fail silently.
UNUserNotificationCenter.current().requestAuthorization(options: [.badge, .alert, .sound]) { (isAuthorized, error) in
// ...
}
Once you're done asking authorization (and the status is granted), simply set your delegate:
UNUserNotificationCenter.current().delegate = self
Create your notification:
let content = UNMutableNotificationContent()
content.title = "Title"
content.subtitle = "Subtitle"
content.body = "Body"
content.sound = UNNotificationSound.default
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 5, repeats: false)
let request = UNNotificationRequest(identifier: "OneDay", content: content, trigger: trigger)
UNUserNotificationCenter.current().add(request) { error in
guard error == nil else {
return
}
// ...
}
And your delegate methods will get called as expected:
extension AppDelegate: UNUserNotificationCenterDelegate {
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void) {
// ...
completionHandler([.alert, .badge, .sound])
}
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: #escaping () -> Void) {
if response.notification.request.identifier == "OneDay" {
// ...
}
completionHandler()
}
}
Adding onto #user13639548 answer:
Make sure to register the current UNUserNotificationCenter.current().delegate each time the app is restarted.
if UserStorage.shared.pushNotificationsToken == nil {
SettingsHelper.getUserPushNotificationStatus(completion: self.processPushNotificationStatus(status:))
} else {
UIApplication.shared.appDelegate?.setAppDelegateAsPushNotificationDelegate()
}
}
This is the resulting call:
func setAppDelegateAsPushNotificationDelegate() {
UNUserNotificationCenter.current().delegate = self
}
When user app into the background and tap on notification.
then the method 'applicationWillEnterForeground' of life cycle is called.
this code is working for me.
func applicationWillEnterForeground(_ application: UIApplication) {
let center = UNUserNotificationCenter.current()
center.delegate = self
}

Displaying local notifications when app starts up in iOS

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)

Setting UserNotification with date from a realm database swift

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

Local Notifications swift 3

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.

Resources