Rewrite `UNNotificationServiceExtension` sub class into Swift 6 async await notation

I'm trying to rewrite a Swift code to Swift 6 language mode and am stuck with this problem. How do I safely pass the bestAttemptContent and contentHandler to the Task? This is from the UNNotificationServiceExtension subclass.

final class NotificationService: UNNotificationServiceExtension {
    
      var contentHandler: ((UNNotificationContent) -> Void)?
      var bestAttemptContent: UNMutableNotificationContent?
      var customNotificationTask: Task<Void, Error>?
    
      override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
        self.contentHandler = contentHandler
        bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent)
        guard let bestAttemptContent = bestAttemptContent else {
    
          invokeContentHandler(with: request.content)
          return
        }
    
        do {
          let notificationModel = try PushNotificationUserInfo(data: request.content.userInfo)
          guard let templatedImageUrl = notificationModel.templatedImageUrlString,
                let imageUrl = imageUrl(from: templatedImageUrl) else {
            invokeContentHandler(with: bestAttemptContent)
            return
          }
          setupCustomNotificationTask(
            imageUrl: imageUrl,
            bestAttemptContent: bestAttemptContent,
            contentHandler: contentHandler
          )
        } catch {
          invokeContentHandler(with: bestAttemptContent)
        }
      }
    
      // More code
    
      private func downloadImageTask(
            imageUrl: URL,
            bestAttemptContent: UNMutableNotificationContent,
            contentHandler: @escaping (UNNotificationContent) -> Void
      ) {
            self.customNotificationTask = Task {
              let (location, _) = try await URLSession.shared.download(from: imageUrl)
              let desiredLocation = URL(fileURLWithPath: "\(location.path)\(imageUrl.lastPathComponent)")
              
                try FileManager.default.moveItem(at: location, to: desiredLocation)
                let attachment = try UNNotificationAttachment(identifier: imageUrl.absoluteString, url: desiredLocation, options: nil)
              bestAttemptContent.attachments = [attachment]
              contentHandler(bestAttemptContent)
            }
       }
    }

I tried using the MainActor.run {}, but it just moved the error to that run function. The UNNotificationRequest is not sendable, and I don't think I can make it so. Wrap the setupCustomNotification in a Task will move the errors to the didReceive method. It seems like the consuming keyword will help here, but it leads to a compilation error, even with the latest Xcode (16.2). Any pointers?

I am in the middle of struggling with Swift6 and facing the same compile error, too.

URLSession methods demand @Sendable in their closures.

How about using Kingfisher's downloder?

import Kingfisher
...
let downloader = ImageDownloader.default
downloader.downloadImage(with: url) { result in
    switch result {
    case .success(let value):
       //value.originalData is Data
       ...
        contentHandler(bestAttemptContent)
    case .failure(_):
        contentHandler(bestAttemptContent)
    }
}
...

or using NSData.init?(contentsOf url: URL) (This runs synchronously, not an ideal solution but very simple one)

https://developer.apple.com/documentation/foundation/nsdata/1413892-init

At least, this compile error vanishes with any of these. (Currently we have too many compile errors with Swift6.)

Have you made any progress here? I'm facing this issue as well, with UNNotificationContent as well as the contentHandler not being Sendable

Rewrite `UNNotificationServiceExtension` sub class into Swift 6 async await notation
 
 
Q