Media Attachment in iOS 10 Push Notifications
Asked Answered
U

3

3

I'm struggling with adding an image to my Push Notification in iOS 10.

I have added a Notification Service Extension, and have used the following code:

        override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
    self.contentHandler = contentHandler
    bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent)


    if let urlString = request.content.userInfo["image-url"] as? String, let fileUrl = URL(string: urlString) {
        URLSession.shared.downloadTask(with: fileUrl) { (location, response, error) in
            if let location = location {
                let options = [UNNotificationAttachmentOptionsTypeHintKey: kUTTypePNG]
                if let attachment = try? UNNotificationAttachment(identifier: "", url: location, options: options) {
                    self.bestAttemptContent?.attachments = [attachment]
                }
            }
            self.contentHandler!(self.bestAttemptContent!)
            }.resume()
    }
}

I got this code from the first answer below.

The issue I'm having now is that the notification is received, with a short delay which indicates the download must be happening, but there is no attachment shown.

I am assuming that serviceExtensionTimeWillExpire() is being called and just showing the bestAttempt

Any help is greatly appreciated.

I have my APNs payload configured correctly, I believe:

apns: {
  aps: { 
    alert: { 
      title: "Title", 
      subtitle: "Subtitle", 
      body: "Body"
    }, 
    "mutable-content": 1
  },
  "image-url": "https://helloworld.com/image.png" 
}
Urano answered 8/9, 2016 at 19:53 Comment(0)
M
4

You have to pull the url out of the notification's user info, then download the image and give a file url to the attachment. Try something like:

if let urlString = request.content.userInfo["image-url"] as? String, let fileUrl = URL(string: urlString) {
    URLSession.shared.downloadTask(with: fileUrl) { (location, response, error) in
        if let location = location {
            let options = [UNNotificationAttachmentOptionsTypeHintKey: kUTTypePNG]
            if let attachment = try? UNNotificationAttachment(identifier: "", url: location, options: options) {
                self.bestAttemptContent.attachments = [attachment]
            }
        }

        self.contentHandler(self.bestAttemptContent)
    }.resume()
}  
Milklivered answered 8/9, 2016 at 20:2 Comment(1)
I can't seem to use my updated code for movies or gifs, only images. Any suggestions?Urano
U
0

I've managed to work this out with the following code:

Swift:

if let PusherNotificationData = request.content.userInfo["data"] as? NSDictionary {
            if let urlString = PusherNotificationData["image-url"] as? String, let fileUrl = URL(string: urlString) {
                URLSession.shared.downloadTask(with: fileUrl) { (location, response, error) in
                    if let location = location {
                        let options = [UNNotificationAttachmentOptionsTypeHintKey: kUTTypePNG]
                        if let attachment = try? UNNotificationAttachment(identifier: "", url: location, options: options) {
                            self.bestAttemptContent?.attachments = [attachment]
                        }
                    }

                    self.contentHandler!(self.bestAttemptContent!)
                    }.resume()
            }
        }

Node:

apns: {
    aps: { 
      alert: { 
        title: "title", 
        subtitle: "subtitle", 
        body: "body"
        }, 
        "mutable-content": 1,
        category: "test"
      },
    data: {
      "image-url": "www.helloworld.com/image.png"
    } 
  }

Thanks for your help!

Urano answered 12/9, 2016 at 14:51 Comment(1)
I cannot seem to add a Gif or a Video by changing the file type hint. Also, removing this option stop my image from being loaded. It should still infer the file type from the url, right?Urano
S
0

Another solution (and a testable one) could be writing the image in a temporally location:

    // NotificationRequestHandler
    func getImageURL(from userInfo: [AnyHashable: Any]) throws -> URL {
        // parse the image URL and return it, otherwise throws and error
    }

    func temporaryWriteData(from url: URL) throws -> (String, URL) {
        let temporaryDirectoryUrl = URL(fileURLWithPath: NSTemporaryDirectory(), isDirectory: true)
        let temporaryFileName = UUID().uuidString
        let temporaryFileUrl = temporaryDirectoryUrl.appendingPathComponent(temporaryFileName)

        let data = try Data(contentsOf: url)
        try data.write(to: temporaryFileUrl, options: .atomic)
        return (temporaryFileName, temporaryFileUrl)
    }

and on didReceive(_:withContentHandler:):

    self.contentHandler = contentHandler
    bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent)

    defer {
        contentHandler(bestAttemptContent ?? request.content)
    }

    do {
        let handler = NotificationRequestHandler()
        let imageUrl = try handler.getImageURL(from: request.content.userInfo)
        let (imageFileName, imageFileUrl) = try handler.temporaryWriteData(from: imageUrl)
        let attachment = try UNNotificationAttachment(identifier: imageFileName, url: imageFileUrl, options: [UNNotificationAttachmentOptionsTypeHintKey: "public.png"])
        bestAttemptContent?.attachments = [attachment]
    } catch {}

Also something very helpful to debug extensions and how to test extentions

Smear answered 24/10, 2019 at 10:1 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.