Skip to content

Instantly share code, notes, and snippets.

@yerffejytnac
Created March 1, 2026 18:21
Show Gist options
  • Select an option

  • Save yerffejytnac/b0770f2b2c8e86b2e5ac5f29619fd53a to your computer and use it in GitHub Desktop.

Select an option

Save yerffejytnac/b0770f2b2c8e86b2e5ac5f29619fd53a to your computer and use it in GitHub Desktop.
expo notification service/target
https://github.com/expo/expo/pull/36202/changes
import UserNotifications
class NotificationService: UNNotificationServiceExtension {
var contentHandler: ((UNNotificationContent) -> Void)?
var bestAttemptContent: UNMutableNotificationContent?
override func didReceive(
_ request: UNNotificationRequest,
withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void
) {
self.contentHandler = contentHandler
bestAttemptContent =
(request.content.mutableCopy() as? UNMutableNotificationContent)
if let bestAttemptContent = bestAttemptContent {
if let userInfo = request.content.userInfo["body"] as? [String: Any],
let richContent = userInfo["_richContent"] as? [String: Any],
let imageUrlString = richContent["image"] as? String,
let imageUrl = URL(string: imageUrlString) {
downloadAndAttachImage(url: imageUrl, to: bestAttemptContent) { content in
contentHandler(content)
}
} else {
contentHandler(bestAttemptContent)
}
}
}
private func downloadAndAttachImage(
url: URL,
to content: UNMutableNotificationContent,
completion: @escaping (UNNotificationContent) -> Void
) {
let task = URLSession.shared.downloadTask(with: url) { temporaryFileLocation, _, error in
guard let temporaryFileLocation = temporaryFileLocation else {
completion(content)
return
}
let fileManager = FileManager.default
let tempDirectory = URL(fileURLWithPath: NSTemporaryDirectory())
let targetFileName = temporaryFileLocation.lastPathComponent + ".jpg"
let targetUrl = tempDirectory.appendingPathComponent(targetFileName)
try? fileManager.removeItem(at: targetUrl)
do {
try fileManager.moveItem(at: temporaryFileLocation, to: targetUrl)
let attachment = try UNNotificationAttachment(
identifier: "image",
url: targetUrl,
options: nil
)
content.attachments = [attachment]
} catch {
print("Error processing attachment: \(error.localizedDescription)")
}
completion(content)
}
task.resume()
}
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)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment