如何从Notification Center移除Remote Notifications并实现同类型通知聚合?
Got it, let’s put together a full solution for aggregating similar remote notifications using a Notification Service Extension—since you already have access to the counter in the userInfo dictionary, this should slot right into your existing setup.
Core Approach
The idea is to track existing notifications for the same post, remove the old one when a new comment comes in, and replace it with an aggregated notification showing the total number of comments. We’ll use App Groups to share state between your main app and the extension (they’re separate processes), and UserDefaults to store the current comment count and the ID of the last delivered notification for each post.
Step 1: Set Up App Groups
First, enable App Groups to share data between your app and extension:
- In Xcode, select your project target → go to the Signing & Capabilities tab.
- Click + Capability and add App Groups.
- Create a group ID (e.g.,
group.com.yourcompany.yourapp) and check the box for both your main app target and the Notification Service Extension target.
Step 2: Implement the Notification Service Extension Logic
Open your NotificationService.swift file and update the didReceive(_:withContentHandler:) method with this code:
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 bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent) guard let content = bestAttemptContent, let postID = content.userInfo["postID"] as? String, // Unique ID for the post getting comments let currentTotalComments = content.userInfo["commentCount"] as? Int else { // Total comments from your backend contentHandler(content) return } // Access shared UserDefaults via your App Group let groupDefaults = UserDefaults(suiteName: "group.com.yourcompany.yourapp")! let countKey = "commentCount_\(postID)" let notificationIDKey = "notificationID_\(postID)" // Pull existing state (if a previous notification exists) let existingCount = groupDefaults.integer(forKey: countKey) let existingNotificationID = groupDefaults.string(forKey: notificationIDKey) // Remove the old notification from Notification Center if let oldNotificationID = existingNotificationID { UNUserNotificationCenter.current().removeDeliveredNotifications(withIdentifiers: [oldNotificationID]) } // Update the notification body with aggregated text let totalComments = currentTotalComments // Use this if backend sends cumulative counts; if sending incremental, use existingCount + currentTotalComments content.body = totalComments == 1 ? "user 1 commented on your post" : "\(totalComments) users have commented on your post" // Generate a unique ID for the new aggregated notification let newNotificationID = UUID().uuidString content.threadIdentifier = postID // Optional: Groups notifications for the same post visually // Save the updated state to shared UserDefaults groupDefaults.set(totalComments, forKey: countKey) groupDefaults.set(newNotificationID, forKey: notificationIDKey) groupDefaults.synchronize() contentHandler(content) } override func serviceExtensionTimeWillExpire() { // Fallback if the extension times out—deliver the best available content if let contentHandler = contentHandler, let bestAttemptContent = bestAttemptContent { contentHandler(bestAttemptContent) } } }
Step 3: Reset State When User Interacts with the Notification
When the user taps the aggregated notification, reset the comment count for that post so new comments start fresh. Add this logic to your main app’s UNUserNotificationCenterDelegate:
import UserNotifications class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { UNUserNotificationCenter.current().delegate = self return true } func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) { let userInfo = response.notification.request.content.userInfo guard let postID = userInfo["postID"] as? String else { completionHandler() return } // Clear the saved count and notification ID for the tapped post let groupDefaults = UserDefaults(suiteName: "group.com.yourcompany.yourapp")! groupDefaults.removeObject(forKey: "commentCount_\(postID)") groupDefaults.removeObject(forKey: "notificationID_\(postID)") groupDefaults.synchronize() // Add your navigation logic here (e.g., open the post detail screen) completionHandler() } }
Key Notes & Considerations
- Backend Coordination: Ensure your backend sends
postID(unique post identifier) andcommentCount(cumulative total of comments) in the notification’suserInfo. If your backend sends incremental counts (e.g., +1 per new comment), adjusttotalCommentstoexistingCount + currentTotalComments. - Notification Threading: Using
content.threadIdentifier = postIDgroups all notifications for the same post in iOS Notification Center, making it easier for users to follow. - Testing: Send two consecutive notifications for the same post—you should see only the aggregated notification, with the first one removed automatically.
- Edge Cases: The
serviceExtensionTimeWillExpire()method ensures we still deliver content if the extension hits its time limit.
内容的提问来源于stack exchange,提问作者Beygel

