0

My Objective-C iOS app schedules a local notification that has a userInfo dictionary and one small JPEG image attachment.

The image is attached like this:

content.attachments = @[[UNNotificationAttachment attachmentWithIdentifier:myIdentifier 
                        URL:[imageURL filePathURL] 
                        options:@{UNNotificationAttachmentOptionsTypeHintKey : UTTypeJPEG} 
                        error:&error]];

This works fine. The notification is correctly scheduled.

If I ignore the Watch and let the notification appear on my phone's Lock Screen, the image is there.

Going back to the Watch. The Watch app receives the notification, and the didReceive method is called in the NotificationController.

No matter what I try, I can't get the image from the notification.

I've tried converting the image to NSData and adding it to the userInfo dictionary, but the data is too large despite the image actually being only a few Kb.

NotificationController.swift: (image is an Image type, and is sent to the NotificationView to use as the background.)

guard let attachment = notification.request.content.attachments.first
else {
    print("Couldn't get the first attachment, using default image")
    image = Image.init(kDefaultImage)
    return
}

// We get here, so we know there's an attachment
if attachment.url.startAccessingSecurityScopedResource() {
    let imageData = try? Data.init(contentsOf: attachment.url)
    if let imageData = imageData {
        image = Image(uiImage: UIImage(data: imageData) ?? 
                      UIImage.init(imageLiteralResourceName: kDefaultImageMasked))
    }
    attachment.url.stopAccessingSecurityScopedResource()

} else {
    print("Couldn't access the file, using default")
    image = Image.init(kDefaultImageMasked)
}

I always get told I can't access the file in the security scoped bit.

If I take out that check I get Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value because the code doesn't put anything into image.

Obviously I would put the default image in there instead of crashing, but once the Watch app crashes the notification that's shown on the Watch shows the correct image, but it's obviously not using my NotificationView because that crashed. It's using the standard mirror feature to show the notification, so it's completely bypassing my code at that point.

I've also tried this:

if(attachment.url.isFileURL) {
    print("attachment image is a file url")
}

It does print out that it's a file url, and it's: file:///var/mobile/Library/BulletinDistributor/Attachments/com.mycompany.myapp/<UUID>.jpeg.

But this fails, so the file doesn't exist at that path, or I'm not allowed to load files from there (?):

if(FileManager.default.fileExists(atPath: attachment.url.path)) {
    ...

How do I get the image from the attachment? I've tried getting the image as Data, as an Image, as a UIImage. Nothing works.

This was simple to do in the old Objective-C WatchKit extension stuff:

NSArray *attachments = notification.request.content.attachments;
if(attachments.count == 1) {
    [_backgroundGroup setBackgroundImage:attachments[0]];
}

No problems there; it always worked.

Any ideas?

Darkpaw
  • 31
  • 4
  • Maybe put the image as an asset inside the watchApp target and load it in using UIImage(named: "yourasset") - instead of using file system? – Billy Oct 04 '22 at 14:25
  • The image is created by the user, not me, so I can't put it in the assets. – Darkpaw Oct 05 '22 at 15:08

0 Answers0