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.