How to show multiple local notifications? - ios

I have an messaging app,I am using VoIP notifications to send acknowledgement to users. I am firing a local notification each time the PushKit delegate is called.
The current scenario is that the previous notification gets removed and is replaced by a newer one. Is there a way to manage local notifications such that the user can see multiple notifications in their device?
This is the code I have tried:
let notificationContent = UNMutableNotificationContent()
notificationContent.title = "Title"
notificationContent.subtitle = "Subtitle"
notificationContent.body = "Body"
// Add Trigger
let notificationTrigger = UNTimeIntervalNotificationTrigger(timeInterval: 0.01, repeats: false)
// Create Notification Request
let notificationRequest = UNNotificationRequest(identifier: "cocoacasts_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))")
}
}
P.S : I don't want to schedule local notification for a later period

Using for loop to register multiple Notification with the unique identifier https://developer.apple.com/documentation/usernotifications/unnotificationrequest/1649634-identifier?language=objc
let notificationRequest = UNNotificationRequest(identifier: "cocoacasts_local_notification", content: notificationContent, trigger: notificationTrigger)
you should change this identifier "cocoacasts_local_notification" to dynamically reset the unique identifier
let notification = UNMutableNotificationContent()
let notificationTrigger = UNCalendarNotificationTrigger(dateMatching: dayComponent, repeats: true)
let lnMessageId:String = messageDict["Id"] as! String
let dayRequest = UNNotificationRequest(identifier: lnMessageId , content: notification, trigger: notificationTrigger)
UNUserNotificationCenter.current().add(dayRequest, withCompletionHandler: {(_ error: Error?) -> Void in
if error == nil
{
//print("success")
}
else
{
//print("UNUserNotificationCenter Error : \(String(describing: error?.localizedDescription))")
}
})

Related

iOS - Trigger Notification Service Extension through Local Push Notification?

Is it possible to trigger Notification Service Extension through Local Push Notification?
My code snippet
UNUserNotificationCenter.current().removeAllPendingNotificationRequests()
let content = UNMutableNotificationContent()
// Adding title,subtitle,body & badge
content.title = "title"
content.body = "body"
content.sound = UNNotificationSound.default
let aps = ["mutable-content": 1]
let dict = ["aps": aps, "some-key": "some-value"] as [AnyHashable : Any]
content.userInfo = dict
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 10, repeats: false)
let request = UNNotificationRequest(identifier: "SimplifiedIOSNotification", content: content as UNNotificationContent, trigger: trigger)
UNUserNotificationCenter.current().add(request, withCompletionHandler: nil)
No, It is not possible to trigger notification service extension through push notification.
Reason: Service extension lets you customize the content of a remote notification before it is delivered to the user. e.g decrypt the message or download the attachments
but I personally think there is no point of downloading the notification content attachments in service extension because you can always download the attachments before scheduling. e.g
// Download attachment asynchronously
downloadAttachments(data: data) { attachments in
UNUserNotificationCenter.current().removeAllPendingNotificationRequests()
let content = UNMutableNotificationContent()
// Add downloaded attachment here
content.attachments = attachments
// Adding title,subtitle,body & badge
content.title = "title"
content.body = "body"
content.sound = UNNotificationSound.default
// No need of adding mutable content here
let dict = ["some-key": "some-value"] as [AnyHashable : Any]
content.userInfo = dict
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 10, repeats: false)
let request = UNNotificationRequest(identifier: "SimplifiedIOSNotification", content: content as UNNotificationContent, trigger: trigger)
UNUserNotificationCenter.current().add(request, withCompletionHandler: nil)
}
Let me know if you have different use case.
Pleas read the documentation before posting. The first line states:
A UNNotificationServiceExtension object provides the entry point for a Notification Service app extension, which lets you customize the content of a remote notification before it is delivered to the user.

iOS push notifications enabled but not working

I am trying to set push notifications in my app.
I have enabled my APN certificates..
And I have turned push notifications on in Xcode..
I have turned push notifications on in previous xcode projects and it worked fine. This is the code I have..
//add push notifications every 5 hours
func pushNotifications() {
let pushNotification = UNMutableNotificationContent()
pushNotification.title = "Time to track your water useage!"
pushNotification.badge = 1
let minute:TimeInterval = 60.0
let hour:TimeInterval = 60.0 * minute
let eighthDay:TimeInterval = 5 * hour
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: eighthDay, repeats: true)
let request = UNNotificationRequest(identifier: "timerDone", content: pushNotification, trigger: trigger)
UNUserNotificationCenter.current().add(request, withCompletionHandler: nil)
}
I am calling this in my viewdidload func
What am I doing wrong?
You can try this code,
func sendLocalPush() {
let objNotificationContent = UNMutableNotificationContent()
objNotificationContent.title = "Manish Kumar"
objNotificationContent.body = "iOS Developer"
objNotificationContent.userInfo = getUserInfoDict()
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 1.0, repeats: false)
let request = UNNotificationRequest(identifier: "LocalNotification", content: objNotificationContent, trigger: trigger)
/// 3. schedule localNotification
let center = UNUserNotificationCenter.current()
center.add(request, withCompletionHandler: {(_ error: Error?) -> Void in
})
}
Hope this helps.

Local Notification in IOS 11 and swift 4?

My app works perfectly on ios 10 but on ios 11 it does not push local Notification.
Is there any error in my code?
let notificationContent = UNMutableNotificationContent()
let sound = self.defaults.string(forKey: "azan")!
// Configure Notification Content
notificationContent.title = "کاتەکانی بانگ"
notificationContent.sound = UNNotificationSound(named: sound)
//notificationContent.subtitle = self.notificationstring
notificationContent.body = self.notificationstring
// Add Trigger
if(TimeInterval(time) > 0)
{
let notificationTrigger = UNTimeIntervalNotificationTrigger(timeInterval: TimeInterval(time), repeats: false)
// Create Notification Request
let notificationRequest = UNNotificationRequest(identifier: identifier, 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))")
}
}
}

Two different Categories of local Notifications

I created two different functions that each create a new local notification.
func scheduleLocalNotification() {
// Create Notification Content
let notificationContent = UNMutableNotificationContent()
// Configure Notification Content
notificationContent.title = "Notif 1"
notificationContent.subtitle = "Local Notifications"
notificationContent.body = "hellow worlds."
// Set Category Identifier
notificationContent.categoryIdentifier = Notification.Category.tutorial
// Add Trigger
let notificationTrigger = UNTimeIntervalNotificationTrigger(timeInterval: 10.0, repeats: false)
// Create Notification Request
let notificationRequest = UNNotificationRequest(identifier: "cocoacasts_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))")
}
}
}
func scheduleLocalNotification2() {
// Create Notification Content
let notificationContent = UNMutableNotificationContent()
// Configure Notification Content
notificationContent.title = "Notif 2"
notificationContent.subtitle = "Local Notifications"
notificationContent.body = "hellow world + snooze"
// Set Category Identifier
notificationContent.categoryIdentifier = Notification.Category.tutorial
// Add Trigger
let notificationTrigger = UNTimeIntervalNotificationTrigger(timeInterval: 10.0, repeats: false)
// Create Notification Request
let notificationRequest = UNNotificationRequest(identifier: "cocoacasts_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))")
}
}
}
I want the first function to create a normal notification without any actions and the second to create a notification with action button. So I create the following function
func configureUserNotificationsCenter() {
// Configure User Notification Center
UNUserNotificationCenter.current().delegate = self
// Define Actions
let actionReadLater = UNNotificationAction(identifier: Notification.Action.readLater, title: "Read Later", options: [])
let actionShowDetails = UNNotificationAction(identifier: Notification.Action.showDetails, title: "Show Details", options: [.foreground])
let actionUnsubscribe = UNNotificationAction(identifier: Notification.Action.unsubscribe, title: "Unsubscribe", options: [.destructive, .authenticationRequired])
// Define Category
let tutorialCategory = UNNotificationCategory(identifier: Notification.Category.tutorial, actions: [actionReadLater, actionShowDetails, actionUnsubscribe], intentIdentifiers: [], options: [])
// Register Category
UNUserNotificationCenter.current().setNotificationCategories([tutorialCategory])
}
I then call the configureUserNotificationsCenter in viewdidload but this causes all my notifications to have these action buttons. I want only the notifications scheduled using the scheduleLocalNotifications2 function and the notifications with other functions should not have these action buttons. How do I go around making that?
Both methods are using a notificationContent.categoryIdentifier of Notification.Category.tutorial. This is the same category that you are specifying the buttons on, which is why it shows up for both. You need to create a second category identifier for your notification with no buttons

Unable to update local scheduled notification content

In one of the WWDC sessions I got code snippet for updating existing notifications. I don't think it works. Trying to update notification content.
First I request pending notifications from UNUserNotificationCenter which always works. Then I am creating new request to update notification with existing unique identifier.
There's 1 new variable content: String.
// Got at least one pending notification.
let triggerCopy = request!.trigger as! UNTimeIntervalNotificationTrigger
let interval = triggerCopy.timeInterval
let newTrigger = UNTimeIntervalNotificationTrigger(timeInterval: interval, repeats: true)
// Update notificaion conent.
let notificationContent = UNMutableNotificationContent()
notificationContent.title = NSString.localizedUserNotificationString(forKey: "Existing Title", arguments: nil)
notificationContent.body = content
let updateRequest = UNNotificationRequest(identifier: request!.identifier, content: notificationContent, trigger: newTrigger)
UNUserNotificationCenter.current().add(updateRequest, withCompletionHandler: { (error) in
if error != nil {
print("🚫 Couldn't update notification \(error!.localizedDescription)")
}
})
I am unable to catch error. The problem is that notification content body doesn't change.
Update.
I also tried to change trigger with different repeat interval. It doesn't work, notification is repeated with the same original interval it was created with.
Update 2.
Read Chris' answer, trying to go with first option.
let center = UNUserNotificationCenter.current()
center.getPendingNotificationRequests(completionHandler: { (requests) in
for request in requests {
if request.identifier == notificationIdentifier {
// Got at least one pending notification,
// update its content.
let notificationContent = UNMutableNotificationContent()
notificationContent.title = NSString.localizedUserNotificationString(forKey: "new title", arguments: nil)
notificationContent.body = "new body"
request.content = notificationContent // ⛔️ request.content is read only.
}
}
})
As you can see I can't modify original request.
Update 3.
Had go with second "delete first" option. Noticed that calling removePendingNotificationRequests and schedule after, still gives me old notification version. I had to add 1 second delay between calling removePendingNotificationRequests and center.add(request).
Marked Chris' answer as accepted but feel free to share better option.
The problem is that you're not modifying the existing notification, and instead adding a new notification with a duplicate identifier.
Let's tackle the duplicate issue first, the reason this duplicate notification doesn't show up is because the identifier isn't unique. From the docs:
(if identifier is not unique, notifications are not delivered).
You have two options. You can 1) modify the existing Notification, or 2) remove it and add the new one.
For 1, you already have the request, instead of pulling the trigger and identifier out of it, just replace request.content with your updated notificationContent.
For 2, you would just need to add a line before your Add:
UNUserNotificationCenter.current().removePendingNotificationRequests(withIdentifiers: [request!.identifier])
After I've requested to Allow Notifications:
I trigger a notification right from my viewDidLoad but then also trigger another one with the same identifier. At the end the the updatedBody/updatedTitle show up.
import UIKit
import UserNotifications
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let content = UNMutableNotificationContent()
content.title = "Scheduled Task"
content.body = "dumbBody"
content.badge = 1
content.sound = UNNotificationSound.default()
content.categoryIdentifier = "alertCategory"
UNUserNotificationCenter.current().delegate = self
//Setting time for notification trigger
let trigger = UNTimeIntervalNotificationTrigger.init(timeInterval: 3.0, repeats: false)
let request = UNNotificationRequest(identifier:"myIdentifier", content: content, trigger: trigger)
UNUserNotificationCenter.current().add(request, withCompletionHandler: {_ in print(" was registered")})
updateNotification()
}
My update function
func updateNotification(){
let center = UNUserNotificationCenter.current()
var request : UNNotificationRequest?
center.getPendingNotificationRequests{ notifications in
for notificationRequest in notifications{
if notificationRequest.identifier == "myIdentifier"{
request = notificationRequest
center.removeAllPendingNotificationRequests() // Removing this line or keeping it makes NO difference
}
}
let newTrigger = UNTimeIntervalNotificationTrigger.init(timeInterval: 5.0, repeats: false)
// Update notificaion conent.
let notificationContent = UNMutableNotificationContent()
notificationContent.title = "UpdatedTitle"
notificationContent.body = "updatedBody"
let updateRequest = UNNotificationRequest(identifier: request!.identifier, content: notificationContent, trigger: newTrigger)
UNUserNotificationCenter.current().add(updateRequest, withCompletionHandler: { (error) in
print("successfully updated")
if error != nil {
print("🚫 Couldn't update notification \(error!.localizedDescription)")
}
})
}
}
}
In the above snippet: Removing center.removeAllPendingNotificationRequests() would make no difference. Still I would receive the updatedNotification.
For handling incoming notifications
extension ViewController:UNUserNotificationCenterDelegate{
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: #escaping () -> Void) {
print("original identifier was : \(response.notification.request.identifier)")
print("original body was : \(response.notification.request.content.body)")
print("Tapped in notification")
switch response.actionIdentifier {
default:
print("some action was clicked")
}
}
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void) {
print("Notification being triggered")
completionHandler( [.alert,.sound,.badge])
}
}

Resources