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

iOS Swift推送通知:APP打开时不生效,关闭时正常,如何解决?

Hey there! Let's troubleshoot why your push notifications aren't showing up when your iOS app is open—this is a super common pitfall with remote pushes, and it's usually easy to fix once you know the right spots to check.

First, let's break down how iOS handles push notifications:

  • When your app is closed or in the background, iOS automatically displays the notification for you.
  • When your app is in the foreground, iOS hands the notification off to your app instead of showing it directly—you have to explicitly tell the system to display it.

The Fix: Implement the Foreground Notification Delegate Method

The key missing piece is probably the willPresent delegate method from UNUserNotificationCenterDelegate. This method fires when a push arrives while your app is active, and you need to call the completion handler with presentation options to make the notification appear.

Here's how to set this up properly, depending on your app structure:

1. For UIKit Apps (AppDelegate-based)

Make sure your AppDelegate conforms to UNUserNotificationCenterDelegate, sets itself as the delegate, and implements the required method:

import UIKit
import UserNotifications

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate {

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // Set up notification center delegate
        UNUserNotificationCenter.current().delegate = self
        
        // Request necessary notification permissions
        let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound]
        UNUserNotificationCenter.current().requestAuthorization(options: authOptions) { granted, error in
            if let error = error {
                print("Notification auth error: \(error.localizedDescription)")
            }
        }
        
        // Register for remote pushes
        application.registerForRemoteNotifications()
        return true
    }

    // MARK: - UNUserNotificationCenterDelegate
    // This is the critical method for foreground notifications
    func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
        // Tell iOS to show the notification as a banner, play sound, and update the badge
        completionHandler([.banner, .sound, .badge])
    }

    // Handle notification taps (works for foreground/background/closed)
    func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
        // Add your custom tap handling logic here
        print("User tapped notification: \(response.notification.request.content.body)")
        completionHandler()
    }

    // Handle device token registration
    func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
        let tokenString = deviceToken.map { String(format: "%02.2hhx", $0) }.joined()
        print("Device Token: \(tokenString)")
        // Send this token to your backend
    }

    func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
        print("Failed to register for remote pushes: \(error.localizedDescription)")
    }
}

2. For SwiftUI Apps (App Struct-based)

If you're using SwiftUI's @main app structure, use UIApplicationDelegateAdaptor to hook up an AppDelegate with the same logic:

import SwiftUI
import UserNotifications

@main
struct YourAppName: App {
    // Hook up the AppDelegate
    @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate

    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

class AppDelegate: NSObject, UIApplicationDelegate, UNUserNotificationCenterDelegate {
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        UNUserNotificationCenter.current().delegate = self
        
        let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound]
        UNUserNotificationCenter.current().requestAuthorization(options: authOptions) { granted, error in
            if let error = error {
                print("Auth error: \(error)")
            }
        }
        
        application.registerForRemoteNotifications()
        return true
    }

    func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
        completionHandler([.banner, .sound, .badge])
    }

    // Add the other delegate methods (tap handling, token registration) as needed
}

Key Checks to Verify

  • Delegate is Set: Make sure UNUserNotificationCenter.current().delegate = self is called early (like in didFinishLaunchingWithOptions), and the delegate object (AppDelegate) isn't deallocated.
  • Permissions Granted: Confirm your app has been granted alert/sound/badge permissions (check Settings > Your App > Notifications).
  • Payload is Correct: Your push payload should include an alert field (for visible content). If you're sending silent pushes, you'll need content-available: 1, but for visible notifications, alert is required.
  • Debug the Delegate Method: Add a print statement inside willPresent to confirm it's being called when a push arrives while the app is open. If it's not firing, double-check your delegate setup.

Once you implement this, your app should display notifications whether it's open, in the background, or completely closed.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 07:39:00