Swift 4中如何检测已调度通知的触发时机(显示时而非点击后)
嘿,我明白你想要的是当通知实实在在显示在用户屏幕上那一刻就触发操作,而不是等用户点击的时候——这个需求在iOS里是可以实现的,我给你两种靠谱的方案,适配不同的场景:
方案1:用通知中心代理直接监听显示事件(最直接的方式)
这个方法适用于大多数普通场景,不管你的通知是本地还是远程,只要通知准备显示给用户,就会触发回调。
步骤:
- 先在App启动时设置通知中心的代理,比如在
AppDelegate的didFinishLaunchingWithOptions里:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { // 请求通知权限(必须先做这个,否则通知不会显示) UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) { granted, error in if granted { print("通知权限已获取") } } // 设置代理 UNUserNotificationCenter.current().delegate = self return true }
- 实现代理的
willPresent方法——这就是通知即将显示时的回调点:
extension AppDelegate: UNUserNotificationCenterDelegate { func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) { // 这里写你要执行的操作! // 比如记录日志、更新本地数据、触发某个后台任务等等 print("✅ 通知已送达,马上要显示在用户屏幕上了") // 别忘了调用completionHandler,指定通知的展示方式 // 比如让通知显示横幅+播放声音 completionHandler([.banner, .sound]) } }
不管你的APP是在前台还是后台,只要通知到点触发要显示,这个方法都会被调用。
方案2:用Notification Service Extension(适合需要修改通知内容的场景)
如果你不仅要触发操作,还需要在通知显示前动态修改内容(比如下载网络图片、替换文本),可以用这个独立的扩展——它会在通知投递到设备、即将显示时被唤醒执行代码,而且是在独立于主APP的进程里运行,不会影响主APP性能。
步骤:
- 在Xcode里新增一个Target:选择「File」→「New」→「Target」,然后找到「Notification Service Extension」,按照向导创建即可。
- 在自动生成的
NotificationService.swift里,修改didReceive方法:
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) // 这里就是通知即将显示时执行操作的地方! print("🔧 正在处理即将显示的通知,执行自定义操作") // 如果不需要修改通知内容,直接返回原内容即可 if let bestAttemptContent = bestAttemptContent { contentHandler(bestAttemptContent) } } override func serviceExtensionTimeWillExpire() { // 如果操作超时(最多30秒),必须调用contentHandler返回内容,避免通知不显示 if let contentHandler = contentHandler, let bestAttemptContent = bestAttemptContent { contentHandler(bestAttemptContent) } } }
注意:这个扩展和主APP是独立的,如果需要共享数据,得用「App Groups」来实现。
给你现有代码的补充
你已经写了通知内容的创建部分,我补全完整的本地通知调度代码,方便你测试:
// 创建通知内容 let content = UNMutableNotificationContent() content.title = NSString.localizedUserNotificationString(forKey: "foo", arguments: nil) content.body = NSString.localizedUserNotificationString(forKey: "bar", arguments: nil) // 设置触发条件(比如10秒后触发) let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 10, repeats: false) // 创建通知请求(注意identifier要唯一,方便后续管理) let request = UNNotificationRequest(identifier: "MyLocalNotification", content: content, trigger: trigger) // 添加到通知中心 UNUserNotificationCenter.current().add(request) { error in if let error = error { print("通知调度失败:\(error.localizedDescription)") } else { print("通知已成功调度") } }
内容的提问来源于stack exchange,提问作者IanCZane
相关产品推荐
相关产品推荐

