Skip to content

Instantly share code, notes, and snippets.

@acalism
Created March 6, 2018 07:32
Show Gist options
  • Save acalism/a09c8c2ac6c72e9a8faf2a9fc70fafe9 to your computer and use it in GitHub Desktop.
Save acalism/a09c8c2ac6c72e9a8faf2a9fc70fafe9 to your computer and use it in GitHub Desktop.
App Extension: Notification Service
import UserNotifications
import MobileCoreServices
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 {
// Modify the notification content here...
// bestAttemptContent.title = "[modified] \(bestAttemptContent.title)"
tryToFetchAttachment(attemptContent: bestAttemptContent, contentHandler: contentHandler)
}
}
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 {
// Modify the notification content here...
tryToFetchAttachment(attemptContent: bestAttemptContent, contentHandler: contentHandler) // 如果两次都失败,该通知最终还是会显示的,只是没有 attachment 罢了。
}
}
// 消息体顶层填入 image 参数及其指向的图片 url(若不用 https,需在 info.plist 里设置 Allow Arbitrary Loads 为 YES)
private func tryToFetchAttachment(attemptContent: UNMutableNotificationContent, contentHandler: @escaping (UNNotificationContent) -> Void) {
// Modify the notification content here...
guard let s = attemptContent.userInfo[AnyHashable("image")] as? String, let imageURL = URL(string: s) else {
contentHandler(attemptContent)
return
}
URLSession.shared.downloadTask(with: imageURL, completionHandler: { (url, response, error) in
guard error == nil, let fileURL = url else {
return
}
guard let attachment = try? UNNotificationAttachment(identifier: response?.suggestedFilename ?? "image.jpeg", file: FileObject.cacheURL(fileURL), options: nil) else {
return
}
attemptContent.attachments = [attachment]
contentHandler(attemptContent)
}).resume()
}
}
enum FileObject {
case data(Data)
case cacheURL(URL)
}
extension UNNotificationAttachment {
/// Save the image to disk, or move cache file to tmp file
convenience init(identifier: String, file: FileObject, options: [AnyHashable : Any]?) throws {
let attachSubFolderName = ProcessInfo.processInfo.globallyUniqueString
let attachSubFolderURL = URL.init(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(attachSubFolderName, isDirectory: true)
let attachFileURL = attachSubFolderURL.appendingPathComponent(identifier)
try FileManager.default.createDirectory(at: attachSubFolderURL, withIntermediateDirectories: true, attributes: nil)
switch file {
case .cacheURL(let cacheFileURL): // 转移
try FileManager.default.copyItem(at: cacheFileURL, to: attachFileURL)
case .data(let data): // 保存为文件
try data.write(to: attachFileURL, options: [])
}
try self.init(identifier: identifier, url: attachFileURL, options: options)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment