Skip to content

Instantly share code, notes, and snippets.

@kayoslab
Created July 26, 2018 13:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kayoslab/25531f4860afc0c2d1ab5f5c34317b61 to your computer and use it in GitHub Desktop.
Save kayoslab/25531f4860afc0c2d1ab5f5c34317b61 to your computer and use it in GitHub Desktop.
Example implementation for a basic iOS 10 UNNotificationServiceExtension to handle jpg/gif/png files
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
self.bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent)
guard let content = bestAttemptContent else {
#if DEBUG
exitGracefully("bestAttemptContent not a UNMutableNotificationContent")
#endif
return
}
DispatchQueue.main.async { [weak self] in
let userInfo: [AnyHashable: Any] = request.content.userInfo
content.attachments = self?.attachmentsFor(userInfo) ?? []
guard let copy = self?.bestAttemptContent else {
#if DEBUG
self?.exitGracefully("bestAttemptContent is nil")
#endif
return
}
contentHandler(copy)
}
}
override func serviceExtensionTimeWillExpire() {
if let contentHandler = contentHandler, let content = self.bestAttemptContent {
contentHandler(content)
}
}
/// Helper function to extract Attachments from an userInfo object
///
/// - Attribute userInfo: The user info extracted from the notification,
/// which should contain one of the available keys to create
/// a rich push notification.
private func attachmentsFor(_ userInfo: [AnyHashable: Any]) -> [UNNotificationAttachment] {
if let attachmentURLString = userInfo["image-url-png"] as? String {
guard let attachmentURL = URL(string: attachmentURLString),
let imageData = try? Data(contentsOf: attachmentURL),
let attachment = self.save("image.png", data: imageData, options: nil) else {
#if DEBUG
self.exitGracefully("PNG was not saved properly")
#endif
return []
}
return [attachment]
} else if let attachmentURLString = userInfo["image-url-jpg"] as? String {
guard let attachmentURL = URL(string: attachmentURLString),
let imageData = try? Data(contentsOf: attachmentURL),
let attachment = self.save("image.jpg", data: imageData, options: nil) else {
#if DEBUG
self.exitGracefully("JPG was not saved properly")
#endif
return []
}
return [attachment]
} else if let attachmentURLString = userInfo["image-url-gif"] as? String {
guard let attachmentURL = URL(string: attachmentURLString),
let imageData = try? Data(contentsOf: attachmentURL),
let attachment = self.save("image.gif", data: imageData, options: nil) else {
#if DEBUG
self.exitGracefully("GIF was not saved properly")
#endif
return []
}
return [attachment]
}
return []
}
/// Save data object onto disk and return an optional attachment linked to this path.
///
/// - Attributes:
/// - identifier: The unique identifier of the attachment.
/// Use this string to identify the attachment later. If you specify an
/// empty string, this method creates a unique identifier string for you.
/// - data: The data stored onto disk.
/// - options: A dictionary of options related to the attached file.
/// Use the options to specify meta information about the attachment,
/// such as the clipping rectangle to use for the resulting thumbnail.
private func save(_ identifier: String, data: Data, options: [AnyHashable: Any]?) -> UNNotificationAttachment? {
// Create paths
let directory = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(ProcessInfo.processInfo.globallyUniqueString, isDirectory: true)
let fileURL = directory.appendingPathComponent(identifier)
// Write data on disk
try? FileManager.default.createDirectory(at: directory, withIntermediateDirectories: true, attributes: nil)
try? data.write(to: fileURL, options: [])
// Create Notification attachment
return try? UNNotificationAttachment(identifier: identifier, url: fileURL, options: options)
}
/// Something went wrong, so maybe we want to clean up and present a fallback to the user.
///
/// - Attribute reason: The reason why something went wrong.
private func exitGracefully(_ reason: String = "") {
guard let copy = bestAttemptContent?.mutableCopy() as? UNMutableNotificationContent else { return }
copy.title = reason
contentHandler?(copy)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment