UNNotificationAttachment with UIImage or Remote URL

后端 未结 4 1398
旧巷少年郎
旧巷少年郎 2020-12-05 15:02

In my Notification Service Extension I am downloading an image from a URL to show as UNNotificationAttachment in a notification.

So I have

相关标签:
4条回答
  • 2020-12-05 15:19

    From UIImage it seems that it is not possible, all the solutions that I found were downloading the image and store it somewhere locally. Also makes sense because you would have to import UIKit and not sure if it is compatible with extensions (and why import a whole framework when there are simpler solutions).

    Here is a simpler and testable solution and without the need of using a FileManager.

    0 讨论(0)
  • 2020-12-05 15:24

    Here is a complete example how to actually download an image from internet and attach it to a local notification (which is part of the original question).

    let content = UNMutableNotificationContent()
    content.title = "This is a test"
    content.body = "Just checking the walls"
    
    if let url = URL(string: "https://example.com/images/example.png") {
    
        let pathExtension = url.pathExtension
    
        let task = URLSession.shared.downloadTask(with: url) { (result, response, error) in
            if let result = result {
    
                let identifier = ProcessInfo.processInfo.globallyUniqueString                
                let target = FileManager.default.temporaryDirectory.appendingPathComponent(identifier).appendingPathExtension(pathExtension)
    
                do {
                    try FileManager.default.moveItem(at: result, to: target)
    
                    let attachment = try UNNotificationAttachment(identifier: identifier, url: target, options: nil)
                    content.attachments.append(attachment)
    
                    let notification = UNNotificationRequest(identifier: Date().description, content: content, trigger: trigger)
                    UNUserNotificationCenter.current().add(notification, withCompletionHandler: { (error) in
                        if let error = error {
                            print(error.localizedDescription)
                        }
                    })
                }
                catch {
                    print(error.localizedDescription)
                }
            }
        }
        task.resume()
    }
    

    Normally there is no need to recreate the image when the downloaded file already is a valid image. Just copy the downloaded file to the current Temp directory with a unique name and a .png or .jpg extension. It's also not necessary to create a sub directory in the existing Temp directory.

    0 讨论(0)
  • 2020-12-05 15:28

    I've created a blogpost on this subject, focused on GIF images. But it should be easy to rewrite my code for simply images.

    You need to create a Notification Service Extension:

    And include this code:

    final class NotificationService: UNNotificationServiceExtension {
    
        private var contentHandler: ((UNNotificationContent) -> Void)?
        private var bestAttemptContent: UNMutableNotificationContent?
    
        override internal func didReceiveNotificationRequest(request: UNNotificationRequest, withContentHandler contentHandler: (UNNotificationContent) -> Void){
            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 attachmentURL = content.userInfo["attachment-url"] as? String else {
                return failEarly()
            }
    
            guard let imageData = NSData(contentsOfURL:NSURL(string: attachmentURL)!) else { return failEarly() }
            guard let attachment = UNNotificationAttachment.create("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 {
    
        /// Save the image to disk
        static func create(imageFileIdentifier: String, data: NSData, options: [NSObject : AnyObject]?) -> UNNotificationAttachment? {
            let fileManager = NSFileManager.defaultManager()
            let tmpSubFolderName = NSProcessInfo.processInfo().globallyUniqueString
            let tmpSubFolderURL = NSURL(fileURLWithPath: NSTemporaryDirectory()).URLByAppendingPathComponent(tmpSubFolderName, isDirectory: true)
    
            do {
                try fileManager.createDirectoryAtURL(tmpSubFolderURL!, withIntermediateDirectories: true, attributes: nil)
                let fileURL = tmpSubFolderURL?.URLByAppendingPathComponent(imageFileIdentifier)
                try data.writeToURL(fileURL!, options: [])
                let imageAttachment = try UNNotificationAttachment.init(identifier: imageFileIdentifier, URL: fileURL!, options: options)
                return imageAttachment
            } catch let error {
                print("error \(error)")
            }
    
            return nil
        }
    }
    

    For more information you can check my blogpost here: http://www.avanderlee.com/ios-10/rich-notifications-ios-10/

    0 讨论(0)
  • 2020-12-05 15:34
    1. create directory in tmp folder
    2. write the NSData representation of the UIImage into the newly created directory
    3. create the UNNotificationAttachment with url to the file in tmp folder
    4. clean up tmp folder

    I wrote an extension on UINotificationAttachment

    extension UNNotificationAttachment {
    
        static func create(identifier: String, image: UIImage, options: [NSObject : AnyObject]?) -> UNNotificationAttachment? {
            let fileManager = FileManager.default
            let tmpSubFolderName = ProcessInfo.processInfo.globallyUniqueString
            let tmpSubFolderURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(tmpSubFolderName, isDirectory: true)
            do {
                try fileManager.createDirectory(at: tmpSubFolderURL, withIntermediateDirectories: true, attributes: nil)
                let imageFileIdentifier = identifier+".png"
                let fileURL = tmpSubFolderURL.appendingPathComponent(imageFileIdentifier)
                let imageData = UIImage.pngData(image)
                try imageData()?.write(to: fileURL)
                let imageAttachment = try UNNotificationAttachment.init(identifier: imageFileIdentifier, url: fileURL, options: options)
                return imageAttachment
            } catch {
                print("error " + error.localizedDescription)
            }
            return nil
        }
    }
    

    So to create UNUserNotificationRequest with UNUserNotificationAttachment from a UIImage you can simply do sth like this

    let identifier = ProcessInfo.processInfo.globallyUniqueString
    let content = UNMutableNotificationContent()
    content.title = "Hello"
    content.body = "World"
    if let attachment = UNNotificationAttachment.create(identifier: identifier, image: myImage, options: nil) {
        // where myImage is any UIImage
        content.attachments = [attachment] 
    }
    let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 120.0, repeats: false)
    let request = UNNotificationRequest.init(identifier: identifier, content: content, trigger: trigger)
    UNUserNotificationCenter.current().add(request) { (error) in
        // handle error
    }
    

    This should work since UNNotificationAttachment will copy the image file to an own location.

    0 讨论(0)
提交回复
热议问题