UNNotificationAttachment failing to attach image
U

4

11

So the following code is being used to attach an image from local storage url of an image. I check in Terminal to see if the image is stored and it does store the image without any issues. So ruling out any issues with the url itself.

do {
let attachment = try UNNotificationAttachment(identifier: imageTag, url: url, options: nil)
content.attachments = [attachment]
} catch {
print("The attachment was not loaded.")
}

Other code that goes with the creation of UserNotification works fine as it triggers at the correct specified time.

The code always goes to the catch block. Can anybody please point me to the mistake if there is any in the implementation. Please help. Thank you.

Edit: with print(error.localizedDescription) error message is Invalid attachment file URL.

Edit2 : with print(error) error message is Error Domain=UNErrorDomain Code=100 "Invalid attachment file URL" UserInfo={NSLocalizedDescription=Invalid attachment file URL}

Unfrock answered 20/7, 2017 at 23:48 Comment(2)
What error is being thrown in the catch statement? Add it to the question.Impressure
@RoboticCat thank you for replying. The error says Invalid attachment file URL. I checked the URL and it is valid and am able to see the images being stored at the location using Terminal.Unfrock
I
18

I have found the real issue behind it. In apple documentation it is written that the url should be a file url and because of which you might be facing issue.

To solve this I have added image to temporary directory and then added to UNNotificationAttachment .

Please find the code below. (For my use case I was getting an imageURL)

extension UNNotificationAttachment {
    /// Save the image to disk
    static func create(imageFileIdentifier: String, data: NSData, options: [NSObject : AnyObject]?) -> UNNotificationAttachment? {
        let fileManager = FileManager.default
        let tmpSubFolderName = ProcessInfo.processInfo.globallyUniqueString
        let tmpSubFolderURL = NSURL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(tmpSubFolderName, isDirectory: true)

        do {
            try fileManager.createDirectory(at: tmpSubFolderURL!, withIntermediateDirectories: true, attributes: nil)
            let fileURL = tmpSubFolderURL?.appendingPathComponent(imageFileIdentifier)
            try data.write(to: fileURL!, options: [])
            let imageAttachment = try UNNotificationAttachment.init(identifier: imageFileIdentifier, url: fileURL!, options: options)
            return imageAttachment
        } catch let error {
            print("error \(error)")
        }
        return nil
    }
}

data in the argument of this function is Data of image . Below is how did I call this method.

let imageData = NSData(contentsOf: url)
guard let attachment = UNNotificationAttachment.create(imageFileIdentifier: "img.jpeg", data: imageData!, options: nil) else { return  }
            bestAttemptContent?.attachments = [attachment]
Investigator answered 5/12, 2017 at 10:4 Comment(3)
This seems to have worked, makes the url, but still getting the error: Error occurred adding notification Invalid attachment file URL so STUPID how much time I am putting into an image to show on the damned notification.Exigent
For everyone trying this solution, first of all it works. Make sure you are calling contentHandler once. Don't put this code below existing code generated by Xcode. Otherwise, adding attachments to bestAttemptContent won't work. :)Feoffee
Good answer, but no reason to create folder inside NSTemporaryDirectory(). Sometimes creating folder inside temporaryDirectory fails in notification service so don't do it and this answer is golden.Breath
W
15

I also found important and quite weird behaviour of initialization of UNNotificationAttachment object. It was happening to me that I was getting error:

"Invalid attachment file URL"

But it was not happening always. It was happening in case when I used for some notifications same image for attachment. When I made a standalone copy of image for each attachment, it never happened. Then I checked directory when images should be copied ( because I wanted to clean it up ), but I was surprised that there were no images.

It seems that UNNotificationAttachment initialization process is deleting files at given URLs. So when you try to reuse some images, they can be deleted ( probably asynchronously, because I was checking existence of that images and it always returned me true - that file exists ). But UNNotificationAttachment ended up with error you can see above. In my opinion only logic explanation of this error is that file at given URL is deleted during the process of UNNotificationAttachment initialization.

Wester answered 28/6, 2018 at 11:36 Comment(7)
This should be the accepted answer good job busting this insanity @vojta!!Exigent
Yes this is an undocumented behavior for sure. This is what I faced too. It s a shame, but true. " UNNotificationAttachment initialization process is deleting files at given URLs" !!!!!!!Yager
@vojta could you confirm what you meant by I made a standalone copy of an image for each attachment . Do you download two images from the internet or doing something different with the location of URL?Timetable
@Timetable nope, by statement I made a standalone copy of an image for each attachment I mean that I've created local image file using NSFileManager for each UNNotificationAttachment. Hope it helpsWester
I've also got this issue. In my case the cached image file did not contain a file extension (like .png) which lead to the error.Basutoland
Same for me. Missing file extension (.jpg, .png, ...). This is a wild undocumented behavior.Runt
The documentation for UNNotificationAttachment explains this: the system moves the attached files into the attachment data store so that the appropriate processes can access the files. So it doesn't delete the file but it does move it elsewhere.Quintet
E
1

Apple actually makes a statement in their documentation (https://developer.apple.com/documentation/usernotifications/unnotificationattachment)

Apple Docs for UNNotificationAttachment:

... The system validates attachments before displaying the associated notification. ... Once validated, attached files are MOVED into the attachment data store so that they can be accessed by all of the appropriate processes. Attachments located inside an app’s bundle are copied instead of moved.

So, above answers with copying an attachment (image) first into a temporary location before adding as an attachment seem to be the expected solution.

Execratory answered 1/12, 2020 at 15:48 Comment(0)
R
0

In Swift 5. The below code works for me. Hope this helps somebody.

let nsDocumentDirectory = FileManager.SearchPathDirectory.documentDirectory
let nsUserDomainMask = FileManager.SearchPathDomainMask.userDomainMask
let paths = NSSearchPathForDirectoriesInDomains(nsDocumentDirectory, nsUserDomainMask, true)
            
let imageURL = URL(fileURLWithPath: paths.first!).appendingPathComponent("\(fileName).jpg")
let image = UIImage(contentsOfFile: imageURL.path)
let imageData = image?.pngData()
            
if let unwrappedImageData = imageData, let attachement = try? UNNotificationAttachment(data: unwrappedImageData, options: nil) {
    content.attachments = [ attachement ]
}
Reserved answered 22/9, 2021 at 11:57 Comment(1)
is it chatgpt answer? UNNotificationAttachment doesn't have such initializerPedant

© 2022 - 2024 — McMap. All rights reserved.