web-dev-qa-db-fra.com

UNNotificationAttachment avec UIImage ou URL distante

Dans mon Notification Service Extension Je télécharge une image à partir d'une URL pour l'afficher sous la forme UNNotificationAttachment dans une notification.

J'ai donc cette image en tant que UIImage et je ne vois pas la nécessité de l'écrire dans mon répertoire de répertoire d'application/conteneur de groupe sur le disque juste pour configurer la notification.

Existe-t-il un bon moyen de créer un UNNotificationAttachment avec un UIImage? (devrait être applicable aux notifications locales et distantes)

16
MarkHim
  1. créer un répertoire dans le dossier tmp
  2. écrire la représentation NSData du UIImage dans le répertoire nouvellement créé
  3. créer le UNNotificationAttachment avec l'URL dans le dossier tmp
  4. nettoyer le dossier tmp

J'ai écrit une extension sur 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)
            guard let imageData = UIImagePNGRepresentation(image) else {
                return nil
            }
            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
    }
}

Donc pour créer UNUserNotificationRequest avec UNUserNotificationAttachment à partir d'un UIImage vous pouvez simplement faire qc comme ceci

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 that follows the 
    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
}

Cela devrait fonctionner puisque UNNotificationAttachment copiera le fichier image vers un emplacement propre.

25
MarkHim

J'ai créé un blog sur ce sujet, axé sur les images GIF. Mais il devrait être facile de réécrire mon code pour de simples images.

Vous devez créer une extension de service de notification: Notification Service Extension

Et incluez ce 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
    }
}

Pour plus d'informations, vous pouvez consulter mon blog ici: http://www.avanderlee.com/ios-10/rich-notifications-ios-10/

6
Antoine

Voici un exemple complet sur la façon de télécharger une image sur Internet et de la joindre à une notification locale (qui fait partie de la question d'origine).

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()
}

Normalement, il n'est pas nécessaire de recréer l'image lorsque le fichier téléchargé est déjà une image valide. Copiez simplement le fichier téléchargé dans le répertoire Temp actuel avec un nom unique et un .png ou .jpg extension. Il n'est pas non plus nécessaire de créer un sous-répertoire dans le répertoire Temp existant.

0
Ely