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