How to implement rich notifications in ios 10 with Firebase
Asked Answered
C

4

4

I have been looking for a solution for this since quite a while. But I am not able to find anything. I have implemented Push Notifications for iOS using FCM. But I don't know if FCM supports iOS 10 rich notifications. If it does, I didn't find code to implement it. Thanks in advance.

Casiano answered 21/11, 2016 at 5:7 Comment(3)
no .. it doesn't ..Carnahan
Thank you for replying @EICaptainv2.0 . Are you sure about this?? i'm Just being over conscious.Casiano
@EICaptainv2.0 If you can please post a detailed answer, that would be really appreciable. Thank you.Casiano
C
5

I have the same question why rich notification not working.. and the problem is with FCM mutable-content payload .. it turns in to gcm.notification.mutable-content when payload receives and that's why there is a problem which is not resolved yet.

For more information, you can check this issue from github.

Its resolved now.. you can check that link and also check this answer AL.

Carnahan answered 21/11, 2016 at 5:20 Comment(0)
G
3

Just an update in relation with @ElCaptainv2.0's answer.

The mutable_content has been added for FCM:

Currently for iOS 10+ devices only. On iOS, use this field to represent mutable-content in the APNS payload. When a notification is sent and this is set to true, the content of the notification can be modified before it is displayed, using a Notification Service app extension. This parameter will be ignored for Android and web.

Note: The parameter value should be boolean, not Integer.

It was also mentioned in the GitHub thread just a few hours ago by kroikie.

Gaillard answered 16/2, 2017 at 2:34 Comment(9)
I am insert mutable_content in fcm payload but it's doesn't work. When I try to check my code with APNS it's work fine. {"to": "dWB537Nz....", "data": { "message": "Offer!", "mediaUrl": "HTTPS url" }, "notification": { "body": "Enter your message", "sound": "default", "click_action": "reminder", "content-available": 1, "mutable-content": 1 } }Ludendorff
mutable_content should be declared outside notification. Same with content_available. Note that for FCM, it has underscores (_) instead of dashes (-).Gaillard
No worries. I noticed you were the one that posted a related question. I added in an answer. :) Cheers!Gaillard
How do you manage to get the data associated with this payload? It ends up outside of "aps" when arriving on the iPhone which is troublesome.Unskillful
I think you should also state that mutable_content has to be set to 'true' . I thought it was supposed to be set to '1'Pressure
Hi @KiloLoco. Sure, I'll add that in.Gaillard
Hi Guys my notifications { "registration_ids": ["devicetoken"], "mutable_content": true, "data": { "post_details": { "pcm_message": "asdf", "pcm_img_url": "portalvh/15683.jpg", } }, "notification" : { "title" : "demo push", "body" : "this is push body" } } but still one don't call Notification Service Extension where is problem or missing some information I have already set deployment target 10.0 in my whole projectPiled
@AnkurPatel I suggest posting a question along with the details instead of adding a comment here. It's hard to view since formatting in the comments are limited. Cheers!Gaillard
@Gaillard thanks for reply see below my question link #49027523Piled
A
1

The Following worked for me (February 2023)

Step 1 - Add a notification service extension

Step 2 - Add Target to Podfile

Step 3 - Use Extension Helper

Converted to Swift:

//
//  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"
    }
}'
Azo answered 12/3, 2023 at 11:25 Comment(0)
J
0

I was working on this for hours and hours and hours and hours. All my notifications worked fine except the rich notification image would never show. Here is the answer is plain english:

Change this:

"mutable-content": 1 // wrong

To this:

"mutable_content": true // correct

Here is the outgoing payload:

"aps": {
    "alert": {
        "title": "Hello",
        "body": "What do you think of this image?"
    },
    "mutable_content": true
},
"media-url": "https://firebasestorage.googleapis.com/....." 
Jezabella answered 21/2, 2021 at 1:1 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.