You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SwiftUI应用前台无法显示Push Notifications求助

SwiftUI应用前台无法显示推送通知问题

问题详情

  • SwiftUI应用在后台模式下可正常接收推送通知,但前台模式时通知完全不显示。
  • 已查阅资料并实现willPresent notification: UNNotification方法,但问题仍未解决。
  • 使用环境:Xcode 14.3、iOS 16.5

应用通知设置

应用通知设置

现有App Delegate代码

class AppDelegate: NSObject, UIApplicationDelegate {
    
    let gcmMessageIDKey = "gcm.message_id"
    
  func application(_ application: UIApplication,
                   didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
    
      FirebaseApp.configure()
      IQKeyboardManager.shared.enable = true
      /// code for push notifications
      Messaging.messaging().delegate = self
      
      if #available(iOS 10.0, *) {
          // For iOS 10 display notification (sent via APNS)
          UNUserNotificationCenter.current().delegate = self
          
          let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound]
          UNUserNotificationCenter.current().requestAuthorization(
            options: authOptions,
            completionHandler: {_, _ in })
      } else {
          let settings: UIUserNotificationSettings =
          UIUserNotificationSettings(types: [.alert, .badge, .sound], categories: nil)
          application.registerUserNotificationSettings(settings)
      }
      
      application.registerForRemoteNotifications()
      
      
      return true
  }
    /// code for notifications
    func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any],
                        fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {

         if let messageID = userInfo[gcmMessageIDKey] {
             Helper.shared.printDebug("Message ID: \(messageID)")
         }

        Helper.shared.printDebug(userInfo)

        DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
            
            if userInfo["other_data"] as? String == "Request Notification" {
                
                
                NotificationCenter.default.post(name: Notification.Name("request_notification"), object: nil, userInfo: userInfo)
            } else {
                NotificationCenter.default.post(name: Notification.Name("message_notification"), object: nil, userInfo: userInfo)
            }
        }
        
         completionHandler(UIBackgroundFetchResult.newData)
       }
}
/// code for push notifications
extension AppDelegate: MessagingDelegate {
    func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String?) {

      let deviceToken:[String: String] = ["token": fcmToken ?? ""]
        Helper.shared.printDebug("Device token: \(deviceToken)") // This token can be used for testing notifications on 
        
        UserDefaults.standard.set(fcmToken, forKey: UserDefaultEnum.deviceId.rawValue)
    }
}

@available(iOS 10, *)
extension AppDelegate : UNUserNotificationCenterDelegate {

  // Receive displayed notifications for iOS 10 devices.
  func userNotificationCenter(_ center: UNUserNotificationCenter,
                              willPresent notification: UNNotification,
    withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
    let userInfo = notification.request.content.userInfo

    if let messageID = userInfo[gcmMessageIDKey] {
        Helper.shared.printDebug("Message ID: \(messageID)")
    }

      Helper.shared.printDebug(userInfo)

    // Change this to your preferred presentation option
    completionHandler([[.banner, .badge, .sound]])
  }

    func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
        Helper.shared.printDebug(deviceToken)
        
    }

    func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
        Helper.shared.printDebug(error.localizedDescription)
    }

  func userNotificationCenter(_ center: UNUserNotificationCenter,
                              didReceive response: UNNotificationResponse,
                              withCompletionHandler completionHandler: @escaping () -> Void) {
    let userInfo = response.notification.request.content.userInfo

      if let messageID = userInfo[gcmMessageIDKey] {
          Helper.shared.printDebug("Message ID from userNotificationCenter didReceive: \(messageID)")
      }
      Helper.shared.printDebug(userInfo)
      
      DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
          
          if userInfo["other_data"] as? String == "Request Notification" {
              
              NotificationCenter.default.post(name: Notification.Name("request_notification"), object: nil, userInfo: userInfo)
          } else {
              NotificationCenter.default.post(name: Notification.Name("message_notification"), object: nil, userInfo: userInfo)
          }
      }
      
      completionHandler()
  }
}

排查与修复建议

  1. 修正willPresent方法的completionHandler参数
    当前代码传递的是嵌套数组[[.banner, .badge, .sound]],格式错误,应改为单个数组:

    completionHandler([.banner, .badge, .sound])
    

    iOS 14及以上推荐使用.banner,但需确保推送payload包含alert字段,否则即使设置也不会展示通知。

  2. 确认UNUserNotificationCenter代理绑定正确性
    尝试在主线程中设置代理,避免启动时异步问题导致代理未绑定:

    if #available(iOS 10.0, *) {
        DispatchQueue.main.async {
            UNUserNotificationCenter.current().delegate = self
        }
        // ... 其余权限请求代码
    }
    
  3. 检查推送Payload格式
    如果使用FCM推送,必须确保payload包含notification字段(而非仅data字段),示例格式如下:

    {
      "notification": {
        "title": "通知标题",
        "body": "通知内容"
      },
      "data": {
        "other_data": "Request Notification"
      },
      "to": "你的设备FCM Token"
    }
    

    仅传递data字段时,前台不会自动弹出通知,需手动处理展示逻辑。

  4. 验证通知权限状态
    在权限请求的回调中添加日志,确认用户是否授予了通知权限:

    UNUserNotificationCenter.current().requestAuthorization(
        options: authOptions,
        completionHandler: { granted, error in
            Helper.shared.printDebug("通知权限授予:\(granted),错误信息:\(error?.localizedDescription ?? "无")")
        })
    
  5. 确认AppDelegate与SwiftUI应用的关联
    检查@main入口结构体是否正确使用UIApplicationDelegateAdaptor关联AppDelegate:

    @main
    struct YourAppName: App {
        @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
        
        var body: some Scene {
            WindowGroup {
                ContentView()
            }
        }
    }
    

内容的提问来源于stack exchange,提问作者Taimoor Arif

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 20:35:01