macOS: Remote push notification accepted by APNs (HTTP 200) but never displayed — application(_:didReceiveRemoteNotification:) fires instead of willPresent

I'm running a PoC to validate remote push notification delivery on macOS (AppKit, no Storyboard, programmatic setup) using UNUserNotificationCenter.

Environment:

  • macOS Version 26.5 (25F71)
  • Xcode Version 26.2 (17C52)
  • App: sandboxed, entitlements include aps-environment: development, Push Notifications + Background Modes (Remote notifications) capabilities enabled
  • Auth: token-based (.p8 key, ES256 JWT), sent via curl directly to api.sandbox.push.apple.com

Setup:

UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .badge, .sound]) { granted, error in
    if granted { NSApplication.shared.registerForRemoteNotifications() }
}

Delegate implements both:

func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void)

and the legacy:

func application(_ application: NSApplication, didReceiveRemoteNotification userInfo: [String: Any])

Repro steps:

  • App launches, permission granted (true), device token successfully obtained via didRegisterForRemoteNotificationsWithDeviceToken
  • Local notifications (via UNNotificationRequest + UNTimeIntervalNotificationTrigger) work correctly — banner displays, willPresent fires as expected
  • Send a remote push via curl:
curl -v --header "apns-topic: $TOPIC" --header "apns-push-type: alert" \
  --header "authorization: bearer $AUTHENTICATION_TOKEN" \
  --data '{"aps": {"alert": {"title": "Test Title","body": "Test Body"}}}' \
  --http2 https://api.sandbox.push.apple.com/3/device/$DEVICE_TOKEN
  • APNs responds HTTP/2 200 with a valid apns-id — accepted successfully

Observed:

  • No banner appears on screen
  • Notification does not appear in Notification Center either
  • Console log shows application(_:didReceiveRemoteNotification:) fired with the correct payload
  • willPresent is never called for this remote push, despite firing correctly for local notifications in the same session

Question:

Given willPresent is documented to be the method responsible for foreground presentation decisions, and it's working correctly for local notifications, why would a remote alert-type push (with a proper alert dict, no content-available) route only through the legacy didReceiveRemoteNotification path and never reach willPresent/get displayed, despite a 200 response from APNs?

One thing I noticed while investigating: the App ID used for this app (auto-created by Xcode's automatic signing) lists its Platform as "iOS, iPadOS, tvOS, watchOS, visionOS" only — macOS is not checked, even though the app itself is macOS-only and Push Notifications capability shows as enabled. Could this platform scoping on the App ID be responsible for APNs/the OS accepting the push at the network layer but not treating it as "alert-UI eligible" for display? Is macOS required to be explicitly checked as a platform on the App ID for willPresent to be invoked correctly, or is that unrelated?

Any guidance on what determines whether a remote push is routed to the foreground presentation path vs. the legacy background delegate path on macOS would be appreciated.

Following up with some additional findings that narrow this down further.

Wanted to note upfront: I've since replaced the deprecated application(:didReceiveRemoteNotification:) approach and tested using UNUserNotificationCenterDelegate's userNotificationCenter(:didReceive:withCompletionHandler:) and userNotificationCenter(_:willPresent:withCompletionHandler:) as the primary handlers - same underlying issue persists, so this isn't a deprecated-API artifact. The more significant finding: Notification Service Extension and Notification Content Extension are not being invoked at all for remote pushes on macOS in our testing.

  • Sent a payload with mutable-content: 1 (to trigger NSE) and a separate payload with a category matching a registered NCE (both extensions properly configured — targets build/sign cleanly, Info.plist extension points correct)

  • Confirmed the App ID in use has the correct platform selected (including macOS) and Push Notifications capability enabled — ruling out App ID configuration as a factor

  • APNs returns HTTP/2 200 for both payloads

  • Checked Console.app filtered by both extension process names — no log output whatsoever from either extension, not even our own NSLog calls placed at the very start of didReceive(:withContentHandler:) / didReceive(:)

  • System-level usernoted logs confirm the notification is registered into the notification database and then removed, without ever being displayed or invoking either extension

Testing on macOS 26.5 (25F71) / Xcode 26.2 (17C52). Any guidance on what else could prevent these extensions from being invoked, given the network layer clearly accepts and delivers the payload, would be appreciated.

macOS: Remote push notification accepted by APNs (HTTP 200) but never displayed — application(_:didReceiveRemoteNotification:) fires instead of willPresent
 
 
Q