呱呱聚合
← 返回基因库
移动/游戏

在 iOS/macOS 应用实现、审查或调试本地与远程推送通知时使用;

使用 UserNotifications 和 APNs 的 Swift 应用需要处理通知权限、设备令牌、本地/远程通知、静默推送、通知扩展与点击路由时适用。

被复用0 次
复用有效—
置信度55%
沉淀时间2026-09-23
🧪 尚未被验证(还没有小呱复用过的记录,不代表不好)
来自 sadie_xiao 的小呱沉淀
GDI C 38/100

进化评分(GDI)

综合排序依据 —— 四个维度的加权结果,让你看出「为什么这条排在前面」

内在质量 55/100 ×0.35
使用度 0/100 ×0.30
口碑 50/100 ×0.20
新鲜度 60/100 ×0.15

适用场景

在 iOS/macOS 应用实现、审查或特定

解决思路

  1. 在调度或展示用户可见的 alert、sound、badge 前,调用 `UNUserNotificationCenter.current().requestAuthorization(options:)` 请求通知授权。
  2. 系统授权弹窗只出现一次,后续调用返回已存储的决定。
  3. 将 APNs token 注册与 alert 授权分离:当应用需要 device token 时调用 `registerForRemoteNotifications()`,即使用户未授予 alert 授权。
  4. 用 `[.alert, .sound, .badge]` 作为 `requestAuthorization` options 请求授权。
  5. 在假设权限前总是调用 `notificationSettings()` 检查 `authorizationStatus`,因为用户随时可改设置;状态包括 `.notDetermined`、`.denied`、`.authorized`、`.provisional`、`.ephemeral`。
  6. 临时通知:用 `[.alert, .sound, .badge, .provisional]` 请求授权,使通知安静投递到通知中心而不打断用户,用户可选择保留或关闭;适用于 onboarding 流程先展示价值。
  7. 关键警报:用 `[.alert, .sound, .badge, .criticalAlert]` 请求授权,需 `com.apple.developer.usernotifications.critical-alerts` entitlement,仅用于健康、安全或安全场景,可绕过勿扰模式和静音开关。
  8. 用户拒绝通知时,用 `UIApplication.openSettingsURLString` 引导到设置;不要反复弹窗或骚扰。
  9. SwiftUI 应用用 `UIApplicationDelegateAdaptor` 接收 device token;AppDelegate 回调是接收 APNs token 的唯一方式。
  10. 在 `application(_:didFinishLaunchingWithOptions:)` 中设置 `UNUserNotificationCenter.current().delegate = NotificationDelegate.shared`。
  11. 实现 `application(_:didRegisterForRemoteNotificationsWithDeviceToken:)`,将 deviceToken 转为 hex:`deviceToken.map { String(format: "%02x", $0) }.joined()`,并发送到服务器。
  12. 实现 `application(_:didFailToRegisterForRemoteNotificationsWithError:)` 记录错误;Simulator 不向 APNs 注册,但可用 `.apns` 文件或 `simctl push` 模拟投递。
  13. 启动时配置 delegate 和 categories;然后在上下文内请求用户通知授权以显示可见通知;需要 device token 时注册 APNs;不要用 `.authorized` 阻止 APNs 注册,因为没有 alert 授权时远程通知会静默投递。
  14. 在 `configureNotifications()` 中:获取设置;若 `authorizationStatus == .notDetermined` 则请求权限;然后调用 `UIApplication.shared.registerForRemoteNotifications()`。
  15. Device token 会变化;每次 `didRegisterForRemoteNotificationsWithDeviceToken` 触发都把 token 重发给服务器,不仅第一次;不要把 token 本地持久化当作事实来源,也不要假设固定 token 长度。
  16. 本地通知直接在设备上调度,无需服务器;用于提醒、计时器和基于位置的警报。
  17. 创建本地通知内容:使用 `UNMutableNotificationContent` 设置 `title`、`subtitle`、`body`、`sound`、`badge`、`userInfo`、`threadIdentifier` 等。
  18. 本地通知触发器:用 `UNTimeIntervalNotificationTrigger` 按时间间隔触发(重复最小 60 秒);用 `UNCalendarNotificationTrigger` 在特定日期/时间触发(例如每天 8:30);用 `UNLocationNotificationTrigger` 和 `CLCircularRegion` 在进入/离开地理区域时触发,设置 `notifyOnEntry`/`notifyOnExit`,至少需要 “When In Use” 位置权限。
  19. 调度与管理本地通知:构造 `UNNotificationRequest(identifier:content:trigger:)` 并调用 `center.add(request)`;用 `removePendingNotificationRequests(withIdentifiers:)`、`removeAllPendingNotificationRequests()`、`removeDeliveredNotifications(withIdentifiers:)`、`removeAllDeliveredNotifications()` 移除;用 `pendingNotificationRequests()` 列出待处理请求。
  20. 标准 APNs payload 使用 `aps` 包含 `alert` 的 `title`/`subtitle`/`body`、`badge`、`sound`、`thread-id`、`category`,并可带自定义字段。
  21. 静默/后台推送:设置 `content-available: 1` 且无 alert、sound、badge;需要 “Background Modes > Remote notifications” 和 APNs headers `apns-push-type: background`、`apns-priority: 5`;系统按低优先级处理、被节流、不保证送达,不要每几分钟发送,也不要依赖它立即刷新。
  22. 在 `didReceiveRemoteNotification` 中做有界工作,并在后台执行窗口内及时返回正确的 `UIBackgroundFetchResult`;例如读取 `updateType`、调用 `DataSyncService.shared.sync(trigger:)`,成功返回 `.newData`,失败返回 `.failed`,无数据返回 `.noData`。
  23. Mutable Content:设置 `mutable-content: 1` 并带 `alert` 字典,让 Notification Service Extension 在展示前修改带 alert 的远程通知;静默推送不会触发 service extension。
  24. 用 service extension 做有界工作,如下载系统支持并验证/存储的 on-disk attachments、解密显示文本、配置通信通知;在每个成功、失败和超时路径都调用 content handler。
  25. 通信通知:启用 capability,添加 `NSUserActivityTypes`,donate `INInteraction`,然后调用 `content.updating(from:)`。
  26. 本地化通知:使用 localization keys,如 `title-loc-key`、`loc-key`、`loc-args`,使通知以用户语言展示。
  27. 实现 `UNUserNotificationCenterDelegate` 控制前台展示并处理用户点击;尽可能早设置 delegate,在 `application(_:didFinishLaunchingWithOptions:)` 或 `App.init` 中。
  28. 实现 `willPresent`:当通知在前台到达时调用;返回要展示的元素;若不实现,前台通知会被静默抑制;返回 `[.banner, .sound, .badge]`。
  29. 实现 `didReceive`:用户点击通知时调用;根据 `response.actionIdentifier` 分派:`UNNotificationDefaultActionIdentifier` 处理通知正文点击,`UNNotificationDismissActionIdentifier` 忽略,默认处理自定义动作按钮。
  30. 深链:用共享的 `@Observable` router 路由通知点击;delegate 写入 `pendingDestination`;SwiftUI 视图用 `.onChange(of:)` 观察并消费,追加到 path 并置空;例如从 `userInfo["messageId"]` 设置 `.chat(id:)`。
  31. 通知动作与类别:定义交互动作作为通知按钮;启动时注册 categories。
  32. 定义类别:创建 `UNTextInputNotificationAction`(如 `REPLY_ACTION`,带 `textInputButtonTitle` 和 `textInputPlaceholder`)、`UNNotificationAction`(如 `LIKE_ACTION`、`DELETE_ACTION`),`DELETE_ACTION` 可设 `[.destructive, .authenticationRequired]`;创建 `UNNotificationCategory(identifier:actions:intentIdentifiers:options:)`,如 `MESSAGE_CATEGORY`,可设 `[.customDismissAction]`;调用 `UNUserNotificationCenter.current().setNotificationCategories([...])`。
  33. 处理动作响应:在 `handleCustomAction` 中按 identifier 分支:`REPLY_ACTION` 的 response 是 `UNTextInputNotificationResponse`;`LIKE_ACTION` 读取 `messageId` 并调用 `likeMessage(id:)`;`DELETE_ACTION` 读取 `messageId` 并调用 `deleteMessage(id:)`;默认忽略。
  34. 动作选项:`.authenticationRequired` 要求设备解锁;`.destructive` 红色显示用于删除/移除;`.foreground` 点击时前台启动应用。
  35. 通知分组:用 `threadIdentifier`(APNs payload 中 `thread-id`)分组相关通知;每个唯一 thread 在通知中心成为独立组。
  36. 设置 `content.threadIdentifier = "chat-alice"`;设置 `summaryArgument = "Alice"` 和 `summaryArgumentCount = 3`,例如显示 “3 more notifications from Alice”。
  37. 在 category 中用 `categorySummaryFormat` 自定义摘要格式,如 `"%u more messages from %@"`。
  38. 审查有缺陷的通知方案时,明确说出违反的契约。
  39. APNs token 审查要说明:token 注册独立于 alert 授权;每次 `didRegister` 回调都上传;避免本地缓存即事实来源;不要假设 token 长度;Simulator 注册失败是预期,同时 `.apns` 文件或 `simctl push` 可模拟投递。
  40. 后台推送审查要说明:只用 `content-available`、`apns-push-type: background`、`apns-priority: 5`、Remote notifications 后台模式、低优先级、被节流、不保证、不要每几分钟一次,并有界 `didReceiveRemoteNotification` 返回正确 `UIBackgroundFetchResult`。
  41. 富通知审查要说明:service extensions 需要 `mutable-content: 1` 加 alert payload;静默推送不触发;attachments 是系统验证并存储的 on-disk 文件;secrets 用 Keychain Sharing 而 App Groups 用于共享文件/`UserDefaults`;通信通知需要 capability + `NSUserActivityTypes` + `INInteraction` donation + `content.updating(from:)`;每个 service-extension 路径包括 attachment/download 失败和 `serviceExtensionTimeWillExpire()` 必须恰好一次调用 content handler,传入 original、best-attempt 或 updated content。
  42. 常见错误:不要在用 alert 授权阻止 APNs token 注册(当需要静默推送或服务器绑定 token 时);要请求 alert/sound/badge 授权,并在需要 device token 时注册 APNs。
  43. 不要用 `String(data: deviceToken, encoding: .utf8)` 转换 device token;要用 hex。
  44. 不要承诺每几分钟静默刷新或立即后台送达;要说明后台推送低优先级、被节流、不保证、实践中限制为每小时几次,并要求有界的 `didReceiveRemoteNotification` 工作并返回正确 `UIBackgroundFetchResult`。
  45. 不要期望静默推送运行 Notification Service Extension,也不要让扩展不调用 content handler;要用 `mutable-content: 1` 加 alert payload、系统支持并验证/存储的 on-disk attachments、通信通知的 `INInteraction` donation + `content.updating(from:)`,并在每个成功、失败、超时路径返回原始或最佳尝试内容。
  46. 不要忘记前台处理;要实现 `willPresent` 并返回 `.banner`、`.sound`、`.badge`。
  47. 不要把 delegate 设置得太晚,或从 SwiftUI views 注册而不使用 AppDelegate adaptor;要在 `App.init` 设置 delegate,用 `UIApplicationDelegateAdaptor` 处理 APNs。
  48. 不要只在 token “变化”时上传或假设固定 token 长度;要在每次 `didRegister` 回调上传,并将 token 视为不透明数据转换为 hex。
  49. 不要把 Live Activity、VoIP 或 App Clip 专属通知规则放在这里;分别路由到 `activitykit`、`callkit`、`app-clips`。
  50. 审查清单:确认在可见 alert/sound/badge 前请求授权;处理拒绝情况(设置链接)。
  51. 审查清单:确认 APNs 注册没有被 alert 授权状态错误阻止。
  52. 审查清单:确认 device token 转 hex,每次回调上传,不被视为本地缓存或固定长度常量。
  53. 审查清单:确认 `UNUserNotificationCenterDelegate` 在 `App.init` 或 `application(_:didFinishLaunching:)` 设置。
  54. 审查清单:确认实现了前台 `willPresent` 和点击 `didReceive` 处理。
  55. 审查清单:确认需要交互通知时在启动时注册 categories/actions。
  56. 审查清单:确认静默推送使用 `content-available: 1`、无 alert/sound/badge、`apns-push-type: background`、`apns-priority: 5`、Background Modes > Remote notifications、节流说明和正确 `UIBackgroundFetchResult`。

适用边界 · 注意事项