Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Attach image to notification given image URL

I want to attach an image to my local notifications given an image URL. This is the extension to create an attachment:

import UserNotifications

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

When I schedule a new notification, I use it like this:

// url of the image such as http://www.unsplash.com/image.png
let data = try? Data(contentsOf: url) 
guard let myImage = UIImage(data: data!) else { return }

if let attachment = UNNotificationAttachment.create(identifier: key, image: myImage, options: nil) {
    content.attachments = [attachment]
}

enter image description here

Creating a notification like this freezes the application for a few seconds because the app downloads the image synchronously. I have also tried to use DispatchQueue but it didn't change anything. What did I do wrong?

like image 324
Cesare Avatar asked Nov 07 '22 22:11

Cesare


1 Answers

Your code downloads an image, parses it to create a UIImage, converts the image back to a block of PNG data, then writes this data to a temporary file.

You can skip the step where you create the UIImage and convert it back to a file.

Try using URLSession and URLDataTask:

let fileURL = ...
let task = URLSession.shared.dataTask(with: url) { (data, _, _) in
    do {
        try imageData.write(to: fileURL)
        let attachment = UNNotificationAttachment.create(identifier: key, image: myImage, options: nil)
        // call closure to call back with attachment and/or error
    }
    catch let ex {
        // call closure with error
    }
}
task.resume()

I've left out some error handling and other details, but this should give you the general idea of what's required to do it asynchronously. URLSessions use GCD to perform asynchronous networking.

like image 91
Dave Weston Avatar answered Nov 14 '22 22:11

Dave Weston