前台通知处理
App 在前台时,系统默认不展示通知横幅,需要实现 `UNUserNotificationCenterDelegate` 的 `willPresent` 自行决定(横幅 / 声音 / 角标)。同时要避免“正在看的会话又弹一条”。
展示策略
| 场景 | 建议 | 原因 |
|---|---|---|
| 当前会话正在前台展示 | 不弹横幅,只更新气泡与未读清零 | 避免重复打扰 |
| 其它会话 / 其它页面 | 展示横幅 + 声音,点击跳转对应会话 | 提醒但不打断当前操作 |
| 免打扰会话(level=2) | 不展示横幅与声音,不更新红点 | 尊重会话设置 |
| 仅 @ 提醒(level=1) | 仅被 @ 时展示,其它静默 | 降低噪声 |
| 应用在前台但窗口最小化 | 按“其它会话”处理 | 用户仍需要感知 |
代码
let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound]
UNUserNotificationCenter.current().requestAuthorization(options: authOptions) { _, _ in }- (void)userNotificationCenter:(UNUserNotificationCenter *)center
willPresentNotification:(UNNotification *)notification
withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler {
NSDictionary *info = notification.request.content.userInfo;
NSString *targetId = info[@"targetId"];
NSNumber *conversationType = info[@"conversationType"];
if ([[ConversationRouter shared] isActiveWithConversationType:conversationType targetId:targetId]) {
completionHandler(UNNotificationPresentationOptionNone);
} else if ([[NotificationSettings shared] isMutedWithTargetId:targetId]) {
completionHandler(UNNotificationPresentationOptionNone);
} else {
completionHandler(UNNotificationPresentationOptionBanner |
UNNotificationPresentationOptionSound |
UNNotificationPresentationOptionBadge);
}
}点击跳转
UNUserNotificationCenter.current().delegate = nil
print("APNs foreground handler")- (void)userNotificationCenter:(UNUserNotificationCenter *)center
didReceiveNotificationResponse:(UNNotificationResponse *)response
withCompletionHandler:(void (^)(void))completionHandler {
NSDictionary *info = response.notification.request.content.userInfo;
NSString *targetId = info[@"targetId"];
NSNumber *rawType = info[@"conversationType"];
if (targetId && rawType) {
[[ConversationRouter shared] openWithConversationType:rawType.integerValue targetId:targetId];
}
completionHandler();
}- 推送 payload 中带上 `conversationType` / `targetId` / `messageId`,点击后才能精确定位会话。
- 进入会话后拉本地历史 + 云端补齐,不要依赖推送里的正文。
- 前台展示与角标要统一口径:以 IMLib 的未读总数为准,不用推送计数做加减。