Does NotificationServiceExtension work with local notifications? - ios

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)

Related

Why I can't mutate fcm push content in NotificationServiceExtension?

I mat the problem with fcm push. I received push notification from our backend and I need change aps title.
For one type of payload notification service extension change title, for another not.
For these payload everything ok:
**POST:** https://fcm.googleapis.com/fcm/send
body:
{
"to" : "my fcm token",
"mutable_content": true,
"notification": {
"title": "{ some code } камера не в сети",
"body": "какое то тело"
},
"data": {
"type": 18990
}
}
Result:
UserInfo:
**type = 18990,**
gcm.message_id = 1669107644621636,
aps = {
alert = {
body = "\U043a\U0430\U043a\U043e\U0435 \U0442\U043e \U0442\U0435\U043b\U043e";
title = "{ some code } \U043a\U0430\U043c\U0435\U0440\U0430 \U043d\U0435 \U0432 \U0441\U0435\U0442\U0438";
};
"mutable-content" = 1;
},
google.c.fid = anyKey,
google.c.sender.id = 0000,
google.c.a.e = 1
But with these I had the problem:
**POST:** https://fcm.googleapis.com/fcm/send
body:
{
"to" : "my fcm token",
"mutable_content": true,
"notification": {
"title": "{ some code } камера не в сети",
"body": "какое то тело"
},
"data": {
"userAgreementId": 18990
}
}
Result:
UserInfo:
**userAgreementId = 18990**,
gcm.message_id = 1669107519431159,
aps = {
alert = {
body = "\U043a\U0430\U043a\U043e\U0435 \U0442\U043e \U0442\U0435\U043b\U043e";
title = "{ some code } \U043a\U0430\U043c\U0435\U0440\U0430 \U043d\U0435 \U0432 \U0441\U0435\U0442\U0438";
};
"mutable-content" = 1;
},
google.c.fid = anyKey,
google.c.sender.id = 0000,
google.c.a.e = 1
title change I did as mentioned in apple documentation (https://developer.apple.com/documentation/usernotifications/modifying_content_in_newly_delivered_notifications)
I override both:
override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: #escaping (UNNotificationContent) -> Void) {
self.contentHandler = contentHandler
bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent)
let userInfo = bestAttemptContent?.userInfo as? [String: Any]
if let bestAttemptContent = bestAttemptContent {
var title = bestAttemptContent.title
if let title_ = ((userInfo?["aps"] as? [String: Any])?["alert"] as? [String: Any])?["title"] as? String {
title = title_
}
title = title.lowercased().contains("камера не в сети") ? "Камера не в сети" : title
bestAttemptContent.title = title
contentHandler(bestAttemptContent)
}
}
and
override func serviceExtensionTimeWillExpire() {
// Called just before the extension will be terminated by the system.
// Use this as an opportunity to deliver your "best attempt" at modified content, otherwise the original push payload will be used.
if let contentHandler = contentHandler, let bestAttemptContent = bestAttemptContent {
let userInfo = bestAttemptContent.userInfo as? [String: Any]
var title = bestAttemptContent.title
if let title_ = ((userInfo?["aps"] as? [String: Any])?["alert"] as? [String: Any])?["title"] as? String {
title = title_
}
title = title.lowercased().contains("камера не в сети") ? "Камера не в сети" : title
bestAttemptContent.title = title
contentHandler(bestAttemptContent)
}
}

Implementing local notifications into MessageKit

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

iOS- FCM not receiving push notification when app is killed

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

All notifications cleared after interacting with one notification

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

Problems in UNCalendarNotificationTrigger in Swift 4

I have problems setting a notification of type UNCalendarNotificationTrigger that is determined by DateComponents
//set content
let content = UNMutableNotificationContent()
content.title = "My Notification Management Demo"
content.subtitle = "Timed Notification"
content.body = "Notification"
content.body = "Notification pressed \(pressed) times"
content.categoryIdentifier = "message"
//set trigger possible problem
let formatted = DateFormatter()
formatted.dateFormat = "yyyy-MM-dd'T'HH:mm:ssxxxxx"
formatted.date(from: "2018-01-19T02:29:50+0000")
var dateInfo = DateComponents()
dateInfo.calendar = formatted.calendar
let trigger = UNCalendarNotificationTrigger(
dateMatching: dateInfo,
repeats: false
)
//Create the request
let request = UNNotificationRequest(
identifier: "my.notification",
content: content,
trigger: trigger
)
//Schedule the request
UNUserNotificationCenter.current().add(request) { (error : Error?) in
print("all ok")
}
And when I make a request to get the pending notifications, the array is wide.
UNUserNotificationCenter.current().getPendingNotificationRequests(completionHandler: {requests -> () in
print("\(requests.count) requests -------")
for request in requests{
print(request.identifier)
}
})

Resources