iOS 10下Firebase通知点击弹窗:APP被杀状态无响应如何解决?
嘿,这个问题我之前帮不少开发者解决过——APP被杀状态下didReceiveRemoteNotification确实不会触发,因为iOS在这种场景下会直接启动APP,不会走这个旧的回调。咱们得换iOS 10之后推出的UserNotifications框架来处理,这才是官方推荐的正确姿势,具体解决方案如下:
解决方案:改用UserNotifications框架实现全状态通知点击弹窗
核心思路是利用UNUserNotificationCenter的代理方法,它能覆盖APP前台、后台、被杀三种状态下的通知点击事件。
1. 初始化配置UserNotifications
在AppDelegate的didFinishLaunchingWithOptions里完成基础配置,同时处理被杀状态下启动APP的通知数据暂存:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { // 确保Firebase初始化已存在 FirebaseApp.configure() // 配置UserNotifications代理与权限 UNUserNotificationCenter.current().delegate = self let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound] UNUserNotificationCenter.current().requestAuthorization(options: authOptions) { granted, error in guard granted else { return } DispatchQueue.main.async { application.registerForRemoteNotifications() } } // 处理被杀状态下点击通知启动APP的情况:暂存通知数据 if let notificationData = launchOptions?[.remoteNotification] as? [AnyHashable: Any] { UserDefaults.standard.set(notificationData, forKey: "PendingNotification") } return true }
2. 实现UNUserNotificationCenterDelegate代理方法
让AppDelegate遵循协议,实现通知接收与点击的回调:
extension AppDelegate: UNUserNotificationCenterDelegate { // APP前台收到通知时的回调(可选,如需前台也弹窗可启用) func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) { // 前台展示系统通知弹窗 completionHandler([.alert, .sound]) // 同时弹出自定义弹窗 showNotificationAlert() } // 点击通知时的回调(覆盖所有状态:后台、被杀) func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) { // 弹出自定义弹窗 showNotificationAlert() completionHandler() } }
3. 处理被杀状态下的弹窗时机
当APP从被杀状态启动时,根ViewController可能还未加载完成,直接弹窗会失败。可以在根VC的viewDidAppear里检查暂存的通知数据:
class RootViewController: UIViewController { override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) // 检查是否有暂存的通知数据 if UserDefaults.standard.object(forKey: "PendingNotification") != nil { showNotificationAlert() // 弹窗后清除暂存数据 UserDefaults.standard.removeObject(forKey: "PendingNotification") } } }
4. 封装通用弹窗方法
把弹窗逻辑抽成通用方法,方便各处调用:
func showNotificationAlert() { DispatchQueue.main.async { guard let rootVC = UIApplication.shared.keyWindow?.rootViewController else { return } let alertController = UIAlertController(title: "Alert", message: "you have a new notification", preferredStyle: .alert) let okAction = UIAlertAction(title: "Yes", style: .default) { _ in // 这里添加点击"Yes"后的业务逻辑 } alertController.addAction(okAction) rootVC.present(alertController, animated: true, completion: nil) } }
关键注意事项
- 推送Payload必须包含
aps字段:Firebase推送时,payload里要带aps节点(哪怕是空的alert),否则系统不会识别为通知消息,点击后无法触发回调。示例Payload:{ "aps": { "alert": {} }, "customData": "your_info" } - 权限校验:必须确保用户授权了通知的
.alert权限,否则弹窗无法展示。 - 场景适配:如果你的APP使用了
SceneDelegate,需要把UNUserNotificationCenter的代理设置在SceneDelegate中,并在scene(_:willConnectTo:options:)里处理启动参数中的通知数据。
内容的提问来源于stack exchange,提问作者desila
相关产品推荐
相关产品推荐

