Prune old NSE notification avatars
The avatar cache files written for Communication Notifications cannot be deleted right after the handler returns (the system reads them lazily, e.g. the Apple Watch fetching the image), and the NSE gets no dismissal callback. Add best-effort, age-based cleanup that drops files older than 24 hours each time a new avatar is written. Notifications are ephemeral, so any device that needed an old file is long done. The cleanup tolerates concurrent NSE instances removing the same file.
This commit is contained in:
@@ -250,9 +250,48 @@ class NotificationService: UNNotificationServiceExtension {
|
||||
return nil
|
||||
}
|
||||
|
||||
pruneOldAvatars(in: avatarsDir)
|
||||
|
||||
return fileURL
|
||||
}
|
||||
|
||||
// Best-effort, age-based cleanup of the avatar cache. We never delete files
|
||||
// right after delivering a notification because the system reads them
|
||||
// lazily (the Apple Watch may fetch the avatar seconds later), and the NSE
|
||||
// gets no "notification dismissed" callback. Instead we drop files old
|
||||
// enough that any device that needed them is long done. Notifications are
|
||||
// ephemeral, so a one-day window is comfortably safe.
|
||||
//
|
||||
// This runs inside the time-limited extension, but the directory holds only
|
||||
// a handful of small files. Every step is best-effort: multiple NSE
|
||||
// instances may run this concurrently, so a file another instance just
|
||||
// removed is expected and harmless (`try?`).
|
||||
func pruneOldAvatars(
|
||||
in directory: URL,
|
||||
olderThan maxAge: TimeInterval = 24 * 60 * 60
|
||||
) {
|
||||
let fileManager = FileManager.default
|
||||
guard
|
||||
let entries = try? fileManager.contentsOfDirectory(
|
||||
at: directory,
|
||||
includingPropertiesForKeys: [.contentModificationDateKey],
|
||||
options: .skipsHiddenFiles
|
||||
)
|
||||
else {
|
||||
return
|
||||
}
|
||||
|
||||
let cutoff = Date().addingTimeInterval(-maxAge)
|
||||
for fileURL in entries {
|
||||
let modified = (try? fileURL.resourceValues(
|
||||
forKeys: [.contentModificationDateKey]
|
||||
))?.contentModificationDate
|
||||
if let modified, modified < cutoff {
|
||||
try? fileManager.removeItem(at: fileURL)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Mutations
|
||||
|
||||
func mutateWithBadge(_ content: UNMutableNotificationContent) {
|
||||
|
||||
Reference in New Issue
Block a user