The expected behavior for my application is to allow multiple, stacked applications and the user should be able to interact with each notification serperately, however when a user clears one notification or uses one of the action buttons on the notification all of my apps notifications are removed from the lock screen. Is there a way to not clear all notifications after one of them is interacted with?
Notification creator function:
func sendNotification (customerName:String) {
let durationString = String(durationDetected!)
let content = UNMutableNotificationContent()
content.title = "Duration: \(durationString)"
content.subtitle = "Customer Name: \(customerName)"
//content.body = "Don't forget to bring coffee."
//content.badge = 1
let customerFacing = UNNotificationAction(identifier:"yes",
title:"Customer Facing",options:[])
let notCustomerFacing = UNNotificationAction(identifier:
"no", title: "Not Customer Facing", options: [])
/*let changeTime = UNTextInputNotificationAction(identifier:
"changeTime", title: "Modify Time", options: [])
let changeName = UNTextInputNotificationAction(identifier:
"changeName", title: "Modify Customer Name", options: [])*/
let category = UNNotificationCategory(identifier: "actionCategory",
actions: [customerFacing, notCustomerFacing],
intentIdentifiers: [], options: [])
content.categoryIdentifier = "actionCategory"
UNUserNotificationCenter.current().setNotificationCategories(
[category])
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 3,
repeats: false)
let eventArrayIndex = LocationService.locationInstance.eventLogArray.count - 1
let requestIdentifier = String(eventArrayIndex)
let request = UNNotificationRequest(identifier: requestIdentifier,
content: content, trigger: trigger)
UNUserNotificationCenter.current().add(request,
withCompletionHandler: { (error) in
// Handle error
})
}
response delegate:
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive
response: UNNotificationResponse, withCompletionHandler completionHandler:
#escaping () -> Void) {
let eventIndexString = response.notification.request.identifier
eventIndex = Int(eventIndexString)!
print("Index \(eventIndex)")
switch response.actionIdentifier {
case "yes":
print("Received")
LocationService.locationInstance.eventLogArray[eventIndex].status = "customerFacing"
let currentID = LocationService.locationInstance.eventLogArray[eventIndex].uniqueID
for (index,element) in LocationService.locationInstance.missedEventArray.enumerated() {
if element.uniqueID == currentID {LocationService.locationInstance.missedEventArray.remove(at: index)}
}
self.commitEventToDatabase(eventObject: LocationService.locationInstance.eventLogArray[eventIndex])
//self.eventLog.reloadData()
case "no":
print(LocationService.locationInstance.eventLogArray.count)
print("WHHHAT")
let currentID = LocationService.locationInstance.eventLogArray[eventIndex].uniqueID
for (index,element) in LocationService.locationInstance.missedEventArray.enumerated() {
if element.uniqueID == currentID {LocationService.locationInstance.missedEventArray.remove(at: index)}
}
LocationService.locationInstance.eventLogArray[eventIndex].status = "notCustomerFacing"
print(LocationService.locationInstance.eventLogArray.count)
//self.eventLog.reloadData()
default:
break
}
completionHandler()
}
Related
I implemented chat using MessageKit and Firebase and was wondering how to implement notifications whenever the user receives a message, I have set up my permissions but I'm having trouble figuring out knowing when a new message is sent. Any ideas would be appreciated.
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
let content = UNMutableNotificationContent()
databaseListener = channelRef?.order(by:"time").addSnapshotListener() { (querySnapshot, error) in
if let error = error {
print(error)
return
}
querySnapshot?.documentChanges.forEach() { diff in
if diff.type == .added {
let snapshot = diff.document
let id = snapshot.documentID
let senderId = snapshot["senderId"] as! String
let senderName = snapshot["senderName"] as! String
let text = snapshot["text"] as! String
let timestamp = snapshot["time"] as! Timestamp
let date = sentTimestamp.dateValue()
let sender = Sender(id: senderId, name: senderName)
let message = ChatMessage(sender: sender, messageId: id, sentDate: date, message: text)
self.messagesList.append(message)
// Notification
content.title = "New message"
content.body = "Tap to respond"
content.categoryIdentifier = AppDelegate.CATEGORY_IDENTIFIER
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 2, repeats: false)
let request = UNNotificationRequest(identifier: ChatMessagesViewController.NOTIFICATION_IDENTIFIER, content: content, trigger: trigger)
UNUserNotificationCenter.current().add(request, withCompletionHandler: nil)
self.messagesCollectionView.insertSections([self.messagesList.count-1])
}
}
}
}
I created a small test project, enabled push notifications and remote notifications and added the template NotificationServiceExtension. When the notification is shown, the title isn't modified as the template would suggest, nor can I attach the debugger to the extension on the simulator.
The notification content has the mutable-content flag set properly, so I would expect it to be called.
{
"aps": {
"alert": {
"title": "Notification Title",
"body": "Notification Body"
},
"badge": 0,
"mutable-content": 1,
"sound": "default",
"category": "richMessage"
}
}
The code I'm using to build the notification:
guard let jsonResult = convertToDictionary(text: incomingData),
let apsData = jsonResult["aps"] as? [String: Any],
let alert = apsData["alert"] as? [String: String],
let title = alert["title"],
let body = alert["body"],
let category = apsData["category"] as? String else { return }
let localNotification = UNMutableNotificationContent()
localNotification.title = title
localNotification.body = body
localNotification.categoryIdentifier = category
let identifier = "SurveyIdentifier"
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 1, repeats: false)
let request = UNNotificationRequest(identifier: identifier, content: localNotification, trigger: trigger)
UNUserNotificationCenter.current().add(request, withCompletionHandler: nil)
I'm trying to trigger local notifications for every 1 minute even in terminated state and background state. But, my app should not trigger notification when time is after 06:00PM. Below is my code.
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 60,repeats: true)
//UNCalendarNotificationTrigger(dateMatching: dateComponents, repeats: true)
// 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.
}
}
}
To handle local notification, try this:
public func addLocalNotification(hour: Int, minute: Int, identifier: String, title: String, body: String) {
// Initialize
let center = UNUserNotificationCenter.current()
// Set its content
let content = UNMutableNotificationContent()
content.title = title
content.body = body
content.sound = .default
// whenever you want to notify user select time
var dateComp = DateComponents()
dateComp.calendar = Calendar.current
dateComp.hour = hour
dateComp.minute = minute
// repeat and date
let trigger = UNCalendarNotificationTrigger(dateMatching: dateComp, repeats: true)
// Initializing the Notification Request object
let req = UNNotificationRequest(identifier: identifier, content: content, trigger: trigger)
// Add the notification to the center
center.add(req) { (error) in
if (error) != nil {
print(error!.localizedDescription)
}
}
}
When my app is killed I am not receiving push notification, but is working fine with the background. After receiving notification I am generating a local notification by getting data from my realm DB. In payload content available key is 1. Please suggest me where I am going wrong, with getting fcm notification or running in the background.
here is my code -
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void) {
let state: UIApplicationState = UIApplication.shared.applicationState
print(userInfo)
if state == .active{
let messageBody = userInfo["aps"] as! Dictionary<String,Any>
print("############# got notification")
if let message = messageBody["message"] {
let messageDict = DCUtilityClass.convertToDictionary(text: message as! String)
let _ = DCPushNotificationAPI.getNotificationResult(info: (messageDict)!)
}
} else if state == .inactive {
let messageBody = userInfo["aps"] as! Dictionary<String,Any>
print("############# got notification")
if let message = messageBody["message"] {
let messageDict = DCUtilityClass.convertToDictionary(text: message as! String)
let _ = DCPushNotificationAPI.getNotificationResult(info: (messageDict)!)
}
} else if state == .background {
let messageBody = userInfo["aps"] as! Dictionary<String,Any>
print("############# got notification")
if let message = messageBody["message"] {
let messageDict = DCUtilityClass.convertToDictionary(text: message as! String)
let _ = DCPushNotificationAPI.getNotificationResult(info: (messageDict)!)
}
}
completionHandler(UIBackgroundFetchResult.noData)
//receiveMessageMethod(recieveMessage: messageBody as! Dictionary<String, Any>)
}
and
class func triggerLocalPushNotification(title:String, body:Dictionary<String,Any>) {
//creating the notification content
let content = UNMutableNotificationContent()
//adding title, subtitle, body and badge
let messageDictModel = DCChatListHistoryModel.init().initWithUserChatDictionary(userDictionary: body)
if messageDictModel.mIsGroup{
if messageDictModel.mGroupDetailsModelArray.count == 0 {
let groupData = DCDBDataUtilityClass.getGroupInfoByConversationId(id: messageDictModel.m_id)
content.title = (groupData?.mGroupsModelArray.first?.mGroup_name)!
content.body = messageDictModel.mlatest_message
} else {
content.title = (messageDictModel.mGroupDetailsModelArray.first?.mGroup_name)!
content.body = messageDictModel.mlatest_message
}
} else {
var messageSender = ""
if messageDictModel.mMessageFrom == UserDefaults.standard.value(forKey: "user_id") as! String {
messageSender = messageDictModel.mMessage_to
} else {
messageSender = messageDictModel.mMessageFrom
}
let name = DCDBDataUtilityClass.getInfoById(id: messageSender)
content.title = (name?.mFull_name)!
content.body = messageDictModel.mlatest_message
}
//getting the notification trigger
//it will be called after 5 seconds
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 0.2, repeats: false)
//getting the notification request
let request = UNNotificationRequest(identifier: "iOSNotification", content: content, trigger: trigger)
//adding the notification to notification center
UNUserNotificationCenter.current().add(request, withCompletionHandler: nil)
}
I have a local notification and I added an action to it. How should I do so that when the action is tapped, the local notification is fired again after 15 minutes?
Here is the code and the extension so that the notification can be showed using an UIImage:
extension UNNotificationAttachment {
static func create(identifier: String, image: UIImage, options: [NSObject : AnyObject]?) -> UNNotificationAttachment? {
let fileManager = FileManager.default
let tmpSubFolderName = ProcessInfo.processInfo.globallyUniqueString
let tmpSubFolderURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(tmpSubFolderName, isDirectory: true)
do {
try fileManager.createDirectory(at: tmpSubFolderURL, withIntermediateDirectories: true, attributes: nil)
let imageFileIdentifier = identifier+".png"
let fileURL = tmpSubFolderURL.appendingPathComponent(imageFileIdentifier)
guard let imageData = UIImagePNGRepresentation(image) else {
return nil
}
try imageData.write(to: fileURL)
let imageAttachment = try UNNotificationAttachment.init(identifier: imageFileIdentifier, url: fileURL, options: options)
return imageAttachment
} catch {
print("error " + error.localizedDescription)
}
return nil
}
}
func scheduleNotification() {
removeNotification()
if shouldRemind && dueDate > Date() {
let content = UNMutableNotificationContent()
content.title = "Reminder:"
content.body = text
content.sound = UNNotificationSound.default()
let calendar = Calendar(identifier: .gregorian)
let components = calendar.dateComponents([.month, .day, .hour, .minute], from: dueDate)
let trigger = UNCalendarNotificationTrigger(dateMatching: components, repeats: false)
let identifier = ProcessInfo.processInfo.globallyUniqueString
if let attachment = UNNotificationAttachment.create(identifier: identifier, image: notificationImage, options: nil) {
content.attachments = [attachment]
}
let action = UNNotificationAction(identifier: "remindLater", title: "Remind me later", options: [])
let category = UNNotificationCategory(identifier: "category", actions: [action], intentIdentifiers: [], options: [])
UNUserNotificationCenter.current().setNotificationCategories([category])
content.categoryIdentifier = "category"
let request = UNNotificationRequest(identifier: "\(itemID)", content: content, trigger: trigger)
let center = UNUserNotificationCenter.current()
center.add(request)
}
}
Just call a modified version scheduleNotification again in the action handler when the user activates the action. I would definitely create a function variable as a TimeInterval or a boolean which determines the trigger time of the notification.