2

Issue:- When getting remote notification have to show image using the imageurl in payload. In Android it’s working fine once we changed the payload. In iOS image not showing in push notification.

Issue facing on Notification Service Extension:- I have added the notification extension and added the code for modifying notification content. This configuration is working fine in native iOS app.

Added the same in the flutter iOS project but there it won’t work. While receiving push notification the extension is not getting called. Just receiving normal notification only. I have tried many scenarios to sort out this issue. Still it’s not working.

Steps i’ve followed:

  • Added code to get notification permission
  • Added Notification extension to the project
  • Used automatically manage signing for profile configuration
  • Added code to modify notification
  • Added imageURL and mutable-content keys in payload

Added the project and payload screenshots here

Notification service class Payload

saurabh
  • 6,687
  • 7
  • 42
  • 63
  • This may help https://firebase.flutter.dev/docs/messaging/notifications/ – Abdul Momen Dec 21 '21 at 09:47
  • Have you tried to active the Notification Service using Objective C, not Swift? I'm referring to https://firebase.flutter.dev/docs/messaging/apple-integration#step-1---add-a-notification-service-extension _Add a product name (use ImageNotification to follow along), set Language to Objective-C and click Finish._ – Zahra Jul 01 '22 at 14:30

1 Answers1

0

I had the issue until I figured out I was not sending the url in data parameter from FCM.

I made it work using these steps from this answer:

Step 1 - Add a notification service extension

Step 2 - Add Target to Podfile

Step 3 - Use Extension Helper

//
//  NotificationService.swift
//  RichNotification
//

import UserNotifications

class NotificationService: UNNotificationServiceExtension {
    var contentHandler: ((UNNotificationContent) -> Void)?
    var bestAttemptContent: UNMutableNotificationContent?
    
    override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
        self.contentHandler = contentHandler
        bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent)
        
        guard let bestAttemptContent = bestAttemptContent,
              let attachmentURLAsString = bestAttemptContent.userInfo["image"] as? String,
              let attachmentURL = URL(string: attachmentURLAsString) else {
            return
        }
        
        downloadImageFrom(url: attachmentURL) { (attachment) in
            if let attachment = attachment {
                bestAttemptContent.attachments = [attachment]
                contentHandler(bestAttemptContent)
            }
        }
    }

    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)
        }
    }
    
    private func downloadImageFrom(url: URL, with completionHandler: @escaping (UNNotificationAttachment?) -> Void) {
        let task = URLSession.shared.downloadTask(with: url) { (downloadedUrl, response, error) in
            // 1. Test URL and escape if URL not OK
            guard let downloadedUrl = downloadedUrl else {
                completionHandler (nil)
                return
            }
            // 2. Get current's user temporary directory path
            var urlPath = URL(fileURLWithPath: NSTemporaryDirectory ())
            // 3. Add proper ending to url path, in the case jpg (The system validates the content of attached files before scheduling the corresponding notification request. If an attached file is corrupted,
            let uniqueURLEnding = ProcessInfo.processInfo.globallyUniqueString + ".jpg"
            urlPath = urlPath.appendingPathComponent (uniqueURLEnding)
            // 4. Move downloadedUrl to newly created urlPath
            try? FileManager.default.moveItem(at: downloadedUrl, to: urlPath)
            // 5. Try adding getting the attachment and pass it to the completion handler
            do {
                let attachment = try UNNotificationAttachment (identifier: "picture", url: urlPath, options: nil)
                completionHandler(attachment)
            }
            catch {
                completionHandler(nil)
            }
        }
        task.resume()
    }
}

extension UNNotificationRequest {
    var attachment: UNNotificationAttachment? {
        guard let attachmentURL = content.userInfo["image"] as? String, let imageData = try? Data(contentsOf: URL(string: attachmentURL)!) else {
            return nil
        }
        return try? UNNotificationAttachment(data: imageData, options: nil)
    }
}

extension UNNotificationAttachment {
    convenience init(data: Data, options: [NSObject: AnyObject]?) throws {
        let fileManager = FileManager.default
        let temporaryFolderName = ProcessInfo.processInfo.globallyUniqueString
        let temporaryFolderURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(temporaryFolderName, isDirectory: true)

        try fileManager.createDirectory(at: temporaryFolderURL, withIntermediateDirectories: true, attributes: nil)
        let imageFileIdentifier = UUID().uuidString + ".jpg"
        let fileURL = temporaryFolderURL.appendingPathComponent(imageFileIdentifier)
        try data.write(to: fileURL)
        try self.init(identifier: imageFileIdentifier, url: fileURL, options: options)
    }
}

cURL to send push notification via Firebase/FCM

curl --location --request POST 'https://fcm.googleapis.com/fcm/send' \
--header 'Authorization: key=<YOUR FCM KEY>' \
--header 'Content-Type: application/json' \
--data-raw '{
    "to": "fcm token for device or channel id",
    "content_available": true,
    "mutable_content": true,
    "notification": {
        "title": "Notification With Image",
        "mutable-content": true,
        "body": "Test Message "
    }, 
    "data": {
        "image": "https://upload.wikimedia.org/wikipedia/commons/1/16/HDRI_Sample_Scene_Balls_%28JPEG-HDR%29.jpg"
    }
}'
saurabh
  • 6,687
  • 7
  • 42
  • 63