I'm trying to implement rich push notifications but I don't get the image at passed url to get displayed. When I open the notification I can only see title, subtitle and body. I'm following the tutorial at https://www.pluralsight.com/guides/creating-ios-rich-push-notifications as I found it suggested in other posts but I'm stuck at showing the image. I also read in one post that I shouldn't run the app but the NotificationExtension but when I do the app crashes when receiving the notification with
Message from debugger: Terminated due to signal 9 Program ended with exit code: 0
message.
This is the print of userInfo when running the app instead :
[AnyHashable("attachment-url"): https://firebasestorage.googleapis.com/v0/b/fix-it-b4b00.appspot.com/o/Prodotti%2FPrato.jpeg?alt=media&token=5d0fde09-2b86-45b0-a383-a11e7e8e241c, AnyHashable("gcm.message_id"): 1560360808567562, AnyHashable("productId"): 9290CEBE-393C-4285-BE7B-B9E2968A1AA0, AnyHashable("aps"): { alert = { body = "Nuova promozione per articolo: Prato"; subtitle = "Negozio: vincenzo calia"; title = "Promozione negozio"; }; "content-available" = 1; "mutable-content" = 1; sound = true; }, AnyHashable("price"): 10.00, AnyHashable("gcm.notification.priority"): high, AnyHashable("google.c.a.e"): 1]
I checked and the url is correct. Could the problem be that the url is not in string format? I put a print to check it but I don't even get the print at beginning of 'didReceive' method. Can you see where is possibly going wrong? As always Many thanks for your interest and time.
These are the function in NotificationService.swift :
override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
print("NotificationService: dide receive called")
self.contentHandler = contentHandler
bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent)
func failEarly() {
contentHandler(request.content)
}
guard let content = (request.content.mutableCopy() as? UNMutableNotificationContent) else {
return failEarly()
}
guard let apnsData = content.userInfo["data"] as? [String: Any] else {
return failEarly()
}
guard let attachmentURL = apnsData["attachment-url"] as? String else {
print("url is not in string form")
return failEarly()
}
guard let imageData = NSData(contentsOf:NSURL(string: attachmentURL)! as URL) else { return failEarly() }
guard let attachment = UNNotificationAttachment.create(imageFileIdentifier: "image.gif", data: imageData, options: nil) else { return failEarly() }
content.attachments = [attachment]
contentHandler(content.copy() as! UNNotificationContent)
}
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 {
contentHandler(bestAttemptContent)
}
}
extension UNNotificationAttachment {
static func create(imageFileIdentifier: String, data: NSData, options: [NSObject : AnyObject]?) -> UNNotificationAttachment? {
let fileManager = FileManager.default
let tmpSubFolderName = ProcessInfo.processInfo.globallyUniqueString
let fileURLPath = NSURL(fileURLWithPath: NSTemporaryDirectory())
let tmpSubFolderURL = fileURLPath.appendingPathComponent(tmpSubFolderName, isDirectory: true)
do {
try fileManager.createDirectory(at: tmpSubFolderURL!, withIntermediateDirectories: true, attributes: nil)
let fileURL = tmpSubFolderURL?.appendingPathComponent(imageFileIdentifier)
try data.write(to: fileURL!, options: [])
let imageAttachment = try UNNotificationAttachment.init(identifier: imageFileIdentifier, url: fileURL!, options: options)
return imageAttachment
} catch let error {
print("error \(error)")
}
return nil
}
}
And this is function that sends the push notification:
static func sendTopicPushNotification(to topic: String, title: String, subtitle: String, body: String, dataUrl: String, productId: String, price: String) {
let serverKey = firebaseServerKey // AAAA8c3j2...
// let topic = "/topics/<your topic here>" // replace it with partnerToken if you want to send a topic
let url = NSURL(string: "https://fcm.googleapis.com/fcm/send")
let postParams: [String : Any] = [
"to": topic,
// "priority": "high",
// "content_available": true,
// "mutable_content": true,
"notification": [
// "badge" : 1, sendig the badge number, will cause aglitch
"body": body,
"title": title,
"subtitle": subtitle,
"text": "some text",
"sound" : true, // or specify audio name to play
"priority": "high",
"content_available": true,
"mutable_content": true
// "category" : "pushNotificationCategory" // "topicPushNotification"
// "click_action" : "", // action when user click notification (categoryIdentifier)
],
"data" : [
"attachment-url": dataUrl,
"productId": productId,
"price": price
]
]
let request = NSMutableURLRequest(url: url! as URL)
request.httpMethod = "POST"
request.setValue("key=\(serverKey)", forHTTPHeaderField: "Authorization")
request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
do {
// request.httpBody = try JSONSerialization.data(withJSONObject: postParams, options: JSONSerialization.WritingOptions())
request.httpBody = try JSONSerialization.data(withJSONObject: postParams, options: [.prettyPrinted]) // working
print("sendTopicPushNotification : My paramaters: \(postParams)")
} catch {
print("sendTopicPushNotification : Caught an error: \(error)")
}
let task = URLSession.shared.dataTask(with: request as URLRequest) { (data, response, error) in
if let realResponse = response as? HTTPURLResponse {
if realResponse.statusCode != 200 {
print("sendTopicPushNotification : Not a 200 response : \(realResponse)")
}
print("sendTopicPushNotification : response : \(realResponse)")
}
if let postString = NSString(data: data!, encoding: String.Encoding.utf8.rawValue) as String? {
print("sendTopicPushNotification : POST: \(postString)")
}
}
task.resume()
}