【问题标题】:UNNotificationAttachment with UIImage or Remote URL带有 UIImage 或远程 URL 的 UNNotificationAttachment
【发布时间】:2016-12-30 09:29:52
【问题描述】:

在我的Notification Service Extension 中,我正在从 URL 下载图像以在通知中显示为 UNNotificationAttachment

所以我有这个图像作为 UIImage 并且看不到需要将它写入我的应用程序目录/磁盘上的组容器中只是为了设置通知。

有没有用 UIImage 创建 UNNotificationAttachment 的好方法? (应该适用于本地和远程通知)

【问题讨论】:

    标签: ios swift uiimage unnotificationserviceextension unnotificationattachment


    【解决方案1】:
    1. 在 tmp 文件夹中创建目录
    2. UIImageNSData 表示写入新创建的目录中
    3. 在 tmp 文件夹中创建带有 url 的 UNNotificationAttachment 文件
    4. 清理 tmp 文件夹

    我在UINotificationAttachment上写了一个扩展

    extension UNNotificationAttachment {
    
        static func create(identifier: String, image: UIImage, options: [NSObject : AnyObject]?) -> UNNotificationAttachment? {
            let fileManager = FileManager.default
            let tmpSubFolderName = ProcessInfo.processInfo.globallyUniqueString
            let tmpSubFolderURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(tmpSubFolderName, isDirectory: true)
            do {
                try fileManager.createDirectory(at: tmpSubFolderURL, withIntermediateDirectories: true, attributes: nil)
                let imageFileIdentifier = identifier+".png"
                let fileURL = tmpSubFolderURL.appendingPathComponent(imageFileIdentifier)
                let imageData = UIImage.pngData(image)
                try imageData()?.write(to: fileURL)
                let imageAttachment = try UNNotificationAttachment.init(identifier: imageFileIdentifier, url: fileURL, options: options)
                return imageAttachment
            } catch {
                print("error " + error.localizedDescription)
            }
            return nil
        }
    }
    

    所以要从UNUserNotificationAttachment 创建UNUserNotificationRequest UIImage 你可以简单地这样做

    let identifier = ProcessInfo.processInfo.globallyUniqueString
    let content = UNMutableNotificationContent()
    content.title = "Hello"
    content.body = "World"
    if let attachment = UNNotificationAttachment.create(identifier: identifier, image: myImage, options: nil) {
        // where myImage is any UIImage
        content.attachments = [attachment] 
    }
    let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 120.0, repeats: false)
    let request = UNNotificationRequest.init(identifier: identifier, content: content, trigger: trigger)
    UNUserNotificationCenter.current().add(request) { (error) in
        // handle error
    }
    

    这应该可以工作,因为UNNotificationAttachment 会将图像文件复制到自己的位置。

    【讨论】:

    • 我没有看到“第 4 步清理 tmp 文件夹”
    • 您将如何处理第 4 步,删除临时文件夹?通知打开后?
    • 使用了临时文件夹,系统自动清理,缓存目录未清理
    • 您的扩展确实有一个额外的右括号。它不会编译。
    • 请注意,iOS 会自动将文件移动到附件数据存储中,因此该文件将立即从临时目录中删除。您无需担心清理工作。
    【解决方案2】:

    我已经创建了一篇关于这个主题的博文,专注于 GIF 图像。但是为简单的图像重写我的代码应该很容易。

    您需要创建一个通知服务扩展:

    并包含以下代码:

    final class NotificationService: UNNotificationServiceExtension {
    
        private var contentHandler: ((UNNotificationContent) -> Void)?
        private var bestAttemptContent: UNMutableNotificationContent?
    
        override internal func didReceiveNotificationRequest(request: UNNotificationRequest, withContentHandler contentHandler: (UNNotificationContent) -> Void){
            self.contentHandler = contentHandler
            bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent)
    
            func failEarly() {
                contentHandler(request.content)
            }
    
            guard let content = (request.content.mutableCopy() as? UNMutableNotificationContent) else {
                return failEarly()
            }
    
            guard let attachmentURL = content.userInfo["attachment-url"] as? String else {
                return failEarly()
            }
    
            guard let imageData = NSData(contentsOfURL:NSURL(string: attachmentURL)!) else { return failEarly() }
            guard let attachment = UNNotificationAttachment.create("image.gif", data: imageData, options: nil) else { return failEarly() }
    
            content.attachments = [attachment]
            contentHandler(content.copy() as! UNNotificationContent)
        }
    
        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)
            }
        }
    
    }
    
    extension UNNotificationAttachment {
    
        /// Save the image to disk
        static func create(imageFileIdentifier: String, data: NSData, options: [NSObject : AnyObject]?) -> UNNotificationAttachment? {
            let fileManager = NSFileManager.defaultManager()
            let tmpSubFolderName = NSProcessInfo.processInfo().globallyUniqueString
            let tmpSubFolderURL = NSURL(fileURLWithPath: NSTemporaryDirectory()).URLByAppendingPathComponent(tmpSubFolderName, isDirectory: true)
    
            do {
                try fileManager.createDirectoryAtURL(tmpSubFolderURL!, withIntermediateDirectories: true, attributes: nil)
                let fileURL = tmpSubFolderURL?.URLByAppendingPathComponent(imageFileIdentifier)
                try data.writeToURL(fileURL!, options: [])
                let imageAttachment = try UNNotificationAttachment.init(identifier: imageFileIdentifier, URL: fileURL!, options: options)
                return imageAttachment
            } catch let error {
                print("error \(error)")
            }
    
            return nil
        }
    }
    

    有关更多信息,您可以在此处查看我的博文: http://www.avanderlee.com/ios-10/rich-notifications-ios-10/

    【讨论】:

    • 虽然此链接可能会回答问题,但最好在此处包含答案的基本部分并提供链接以供参考。如果链接页面发生更改,仅链接答案可能会失效。有关详细信息,请参阅How to Answer
    • @VinceBowdren 你是完全正确的。改变了我的答案!
    • 什么时候从临时目录中删除图像?
    • 系统自己修剪临时目录。
    • 似乎我们必须使用相同的“普通”文件扩展名,如 jpeg 文件的“.jpg”和 png 等的“.png”等。仅使用没有扩展名的“myfile”之类的通用文件名是不够的。我假设这是 UNNotificationAttachment 或someplace 的弱点。 github.com/lionheart/openradar-mirror/issues/15555
    【解决方案3】:

    这是一个完整的示例,如何实际从互联网下载图像并将其附加到本地通知(这是原始问题的一部分)。

    let content = UNMutableNotificationContent()
    content.title = "This is a test"
    content.body = "Just checking the walls"
    
    if let url = URL(string: "https://example.com/images/example.png") {
    
        let pathExtension = url.pathExtension
    
        let task = URLSession.shared.downloadTask(with: url) { (result, response, error) in
            if let result = result {
    
                let identifier = ProcessInfo.processInfo.globallyUniqueString                
                let target = FileManager.default.temporaryDirectory.appendingPathComponent(identifier).appendingPathExtension(pathExtension)
    
                do {
                    try FileManager.default.moveItem(at: result, to: target)
    
                    let attachment = try UNNotificationAttachment(identifier: identifier, url: target, options: nil)
                    content.attachments.append(attachment)
    
                    let notification = UNNotificationRequest(identifier: Date().description, content: content, trigger: trigger)
                    UNUserNotificationCenter.current().add(notification, withCompletionHandler: { (error) in
                        if let error = error {
                            print(error.localizedDescription)
                        }
                    })
                }
                catch {
                    print(error.localizedDescription)
                }
            }
        }
        task.resume()
    }
    

    当下载的文件已经是有效图像时,通常不需要重新创建图像。只需将下载的文件复制到具有唯一名称和.png.jpg 扩展名的当前临时目录即可。也不必在现有的 Temp 目录中创建子目录。

    【讨论】:

      【解决方案4】:

      来自UIImage 似乎不可能,我找到的所有解决方案都是下载图像并将其存储在本地某处。这也很有意义,因为您必须导入 UIKit 并且不确定它是否与扩展兼容(以及为什么在有更简单的解决方案时导入整个框架)。

      Here 是一种更简单且可测试的解决方案,无需使用 FileManager。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-07-29
        • 1970-01-01
        • 1970-01-01
        • 2011-12-03
        • 2015-06-17
        • 2018-07-29
        相关资源
        最近更新 更多