0

I have a UNNotificationServiceExtension that downloads videos and images to the Documents directory for use by classes that adopt UNNotificationContentExtension. I want to delete the media files that are no longer being used by any notifications. I am not sure how to go about doing this.

  • I tried to delete the files in my AppDelegate, but I believe the UNNotificationServiceExtension has its own Documents directory per the "Sharing Data With Your Containing App" section of this document: https://developer.apple.com/library/archive/documentation/General/Conceptual/ExtensibilityPG/ExtensionScenarios.html, so I cannot access these files from my main app. They are in a different container.
  • I don't want to create an App Group to share the data between the app and the extension just so that I can delete the unused files.
  • I don't want to delete the unused files in the UNNotificationServiceExtension, because the extension has a limited amount of time in which to complete its work, and if I try to download files and delete other files, it may time out.

I think the best option is to check to see which files are needed by any delivered notifications and to delete the unneeded files in the Notification Service Extension's Documents directory. My concern with this is that the UNNotificationServiceExtension is only given a short period of time during which it must complete all of its work, after which it will time out.

So, my question is, "Is this the right way to clean up unused files from a Notification Service Extension, or is there a better way?"

Nick
  • 11
  • 1
  • 4
  • When you clear the notification from your device's notification tray, the media(Notification content) downloaded with the notification is automatically removed by the device. And if you are storing data in some other place explicitly then you have to add App groups in order to store and delete the data. – manishsharma93 Mar 29 '19 at 06:16

1 Answers1

0

Thanks to manishsharma93, I was able to implement a good solution. I am now storing the files in a directory shared by the main app and the notification service extension. I first had to set up a shared App Group using the information found here: https://developer.apple.com/library/archive/documentation/Miscellaneous/Reference/EntitlementKeyReference/Chapters/EnablingAppSandbox.html#//apple_ref/doc/uid/TP40011195-CH4-SW19

Then in my AppDelegate, I added this private function, which I call at the end of the applicationDidFinishLaunching(_:) method:

// I call this at the end of the AppDelegate.applicationDidFinishLaunching(_:) method
private func clearNotificationMedia() {
    // Check to see if there are any delivered notifications. If there are, don't delete the media yet,
    // because the notifications may be using them. If you wanted to be more fine-grained here,
    // you could individually check to see which files the notifications are using, and delete everything else.
    UNUserNotificationCenter.current().getDeliveredNotifications { (notifications) in
        guard notifications.isEmpty else { return }

        let fileManager = FileManager.default

        guard let mediaCacheUrl = fileManager.containerURL(forSecurityApplicationGroupIdentifier: "group.com.yourGroupHere")?.appendingPathComponent("media_cache", isDirectory: true) else { return }

        // Check to see if the directory exists. If it doesn't, we have nothing to do here.
        var isDirectory: ObjCBool = false
        let directoryExists = FileManager.default.fileExists(atPath: mediaCacheUrl.path, isDirectory: &isDirectory)
        guard directoryExists && isDirectory.boolValue else {
            print("No media_cache directory to delete.", terminator: "\n")
            return
        }

        // The directory exists and there aren't any notifications using media stored there,
        // so go ahead and delete it. Use a lock to make sure that there isn't data corruption,
        // since the directory is shared.
        let lock = NSLock()
        lock.lock()
        do {
            try FileManager.default.removeItem(at: mediaCacheUrl)
            DebugLog("Successfully deleted media_cache directory.")
        } catch let error as NSError {
            DebugLog("Error: \(error.localizedDescription). Failed to delete media_cache directory.")
        }
        lock.unlock()
    }
}

It works like a charm. Thanks again for pointing me in the right direction manishsharma93.

Nick
  • 11
  • 1
  • 4