Notifications

RSS for tag

Learn about the technical aspects of notification delivery on device, including notification types, priorities, and notification center management.

Notifications Documentation

Posts under Notifications subtopic

Post

Replies

Boosts

Views

Activity

Issue related to APNS is delivering expired voip push notification.
Hi, am facing an issue related to voip push notifications getting delivered 1-2 hours after apns-expiration to 0 and apns-priority to 10. I had raised a similar post got a reply that it may be due to network delay. But network delay can cause the delivery of voip push to be delayed only by few seconds or minutes. But in our case voip push is getting delivered hours after the voip call was attempted. Steps to reproduce: Put our voip app in background and lock iPhone. As app is put in background, socket connections gets disconnected from server. Now if a caller makes call to this app, the call should be delivered through voip push. 2) Voip push should ideally be received even if app is in background and iPhone is locked. It is connected to a good wifi network. But it does not receive the voip push. 3) After 1-2 hours user unlocks iPhone and opens voip app. As soon as user opens app, the voip push is received and phone starts ringing.
3
0
124
Apr ’25
Custom notification images are confused with those from other apps.
My app uses custom notifications with custom images. Why do these images get mixed up with those from other apps, causing my notifications to display images from other apps? `INImage *avatarImage = [INImage imageWithImageData:imageData]; NSPersonNameComponents *nameComponents = [[NSPersonNameComponents alloc] init]; nameComponents.nickname = content.title; INPersonHandle *handle = [[INPersonHandle alloc] initWithValue:nil type:INPersonHandleTypeUnknown]; INPerson *messageSender = [[INPerson alloc] initWithPersonHandle:handle nameComponents:nameComponents displayName:content.title image:avatarImage contactIdentifier:nil customIdentifier:customIdentifier isMe:NO suggestionType:(INPersonSuggestionTypeNone)]; INSpeakableString *speakableString = [[INSpeakableString alloc] initWithSpokenPhrase:content.subtitle.length ? content.subtitle : @""]; INSendMessageIntent *intent = [[INSendMessageIntent alloc] initWithRecipients:@[messageSender] outgoingMessageType:(INOutgoingMessageTypeOutgoingMessageText) content:content.body speakableGroupName:speakableString conversationIdentifier:identifier serviceName:nil sender:messageSender attachments:nil]; [intent setImage:avatarImage forParameterNamed:@"speakableGroupName"]; INInteraction *interaction = [[INInteraction alloc]initWithIntent:intent response:nil]; interaction.direction = INInteractionDirectionIncoming; [interaction donateInteractionWithCompletion:nil]; UNNotificationContent *_content = [content contentByUpdatingWithProvider:intent error:nil]; UNNotificationRequest *request = [UNNotificationRequest requestWithIdentifier:identifier content:_content trigger:trigger]; [UNUserNotificationCenter.currentNotificationCenter addNotificationRequest:request withCompletionHandler:completionHandler];`
3
1
721
Oct ’24
APNS is delivering expired voip push notification.
I have tried setting a 'apns-expiration' to current time + 30 seconds and also a value '0'. But still my voip app receives the voip push notification after 2-3 minutes. Till this time, caller has already hung up the call. But the receivers phone still rings on receiving the push notification as we have to report it to CallKit. Am I missing something or there is no way and even 'apns-expiration' does not guarantee timely delivery of Voip push notifications or discard if it is expired. I have set 'apns-priority' to 10 already as recommended.
3
0
338
Mar ’25
APNS ERROR
When I use https://api.push.apple.com/3/device/e0ae826f3905b010e37c4a07e873481b8446c9dc2788511b2995992884468068 Return error message: {"reason":"BadDeviceToken"} When I use https://api.development.push.apple.com/3/device/e0ae826f3905b010e37c4a07e873481b8446c9dc2788511b2995992884468068 Return error message:{"reason":"TopicDisallowed"} why?
3
0
259
Mar ’25
Reasons for the prompt "application is damaged and cannot be opened. You should move it to trash"
We have an application which keeps throwing the error "application is damaged and cannot be opened. You should move it to Trash" We have checked the following possible root causes: Codesign of the application using the codesign command Notarization of the application using the spctl command Executable permissions Checked for the presence of "com.apple.quarantine" flag for the application using xattr -l <path to executables" None of the above listed items seemed to be a problem and are as expected. Can you please help us understand what could cause this issue and how to resolve this without recommending an uninstall/reinstall of the application?
3
0
322
Dec ’24
SHA-2 Root: USERTrust RSA Certification Authority certificate.
Got notification to update this certificate - there was a link to Sectigo.com where I found an attachment with that name - when I clicked it I got a box where it said to install it. Clicked the box and it was saved somewhere on my computer. Now I dont know if that's it or I need to take further actions - please help :-) Have no experience with this - my collegue who did this has stopped. Hoping for a simple answer :-) P
3
0
508
Feb ’25
Email VIP Alerts on iPhone Lock Screen
From iPhone iOS 18.3 , 18.3.1, and 18.4 Dev2, VIP Mail alerts will not wake a phone display to notify of a new mail received for a VIP contact. The phone will sound an audible tone indicating the mail was received, and if you manually wake the screen by tapping and then dragging upward to show notifications you will then see the VIP mail alert. However if the screen is sleeping, it will not light up or wake to indicate or display the new mail. The problem was briefly resolved in 18.4 Dev1, but problem returns in Dev2. We see this across all iPhone 16 Pros and iPhone SE2 with iOS 18.3 or higher. Is this something acknowledged by Apple as on track for resolution in iOS 18.4 Final Release? Thank you.
3
1
459
Mar ’25
Batch push issues for commercial apps
The backend service uses the same copy to push to many users in batches. This year, the following problem began to occur. Using http2 send is normal, but when getting the result through the stream id, it always times out. Restarting the service still times out. I hope Apple development engineers can help me find out what the problem is.
2
0
248
Dec ’24
Abnormal Fluctuations in APNs API Response Success Rate (July 15-30)
Observations​​: When our app calls the APNs API for push notifications, we observed significant fluctuations: July 15-25​​: The success response volume ​​increased by 20%​​ compared to the baseline before July 15. ​​After July 25​​: Success rates returned to baseline levels. July 30​​: Success response volume ​​decreased by 10%​​ compared to the pre-July 15 baseline. ​​ Excluded Factors​​: No changes in target audience size or characteristics (business factors ruled out). Server logs confirm consistent API request parameters and frequency. ​​Key Questions​​: Were there any ​​adjustments to response metrics​​ (e.g., success status code definitions) during this period? Have other developers reported similar issues? Were there server-side configuration updates or known incidents on Apple’s end?
2
1
192
Aug ’25
iOS 18.2 Heavy Delays in Notifications with AI enabled
I am experiencing heavy delays with any push notification if I have AI enabled. Authenticator takes minutes to show up, the app for the doorbell that, needless to say, requires a real-time notification, fails to deliver push notifications in time. I have had to turn off AI in order to have a functioning phone... (I'm on a 16 Pro) Any resolution on this? Thanks
2
1
846
Dec ’24
Push Notification Gets Removed From Notification Screen When Setting "badge" to 0
Push message on the lock-screen disappears in one specific instance. In general the situation is as follows: the application, upon starting up, sets the badge counter (i.e. notificationCenter.setBadgeCount(3)) the application is being sent to background the screen is locked (it doesn't matter if it's turned on or not) send a push message to the application and set the badge (in aps) to "0" What happens: the screen lights up (unless it's lit up already), the push is being displayed for a very short time and gets hidden. Happens on iOS 18.1, 18.1.1, 18.2. If not setting badge in the aps keys it works correctly. I've created a feedback report https://feedbackassistant.apple.com/feedback/16095572. I am able to reproduce the issue on a sample app 100% of the time :/
2
0
551
Dec ’24
Silent push notifications not received
I have a flutter app which receives bot alert and silent notifications. The alert notifications are received properly whilst the silent ones do not trigger any function. My app is based on OneSignal but for the testing i am also trying to directly send the notifications using the APN console. Using either alert or background type notification I am using real device (iPhone XR) The background modes are set to "Background fetch" and "Remote notifications" The token is valid as i am getting alert notifications. The app has notification permissions. The didReceiveRemoteNotification never gets triggered (for alert or silent types) When sending alert notification i do see the printout of "willPresent notification" Here is my AppDelegate.swift code. @objc class AppDelegate: FlutterAppDelegate { override func application( _ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data ) { // Log device token to ensure correct registration let tokenParts = deviceToken.map { data in String(format: "%02.2hhx", data) } let token = tokenParts.joined() print("Device Token: \(token)") } override func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? ) -> Bool { // Request full notification permissions UNUserNotificationCenter.current().requestAuthorization( options: [.alert, .badge, .sound, .provisional, .criticalAlert] ) { (granted, error) in print("Notification Authorization Granted: \(granted)") if let error = error { print("Notification Authorization Error: \(error.localizedDescription)") } // Always attempt to register for remote notifications DispatchQueue.main.async { UIApplication.shared.registerForRemoteNotifications() } } // Set notification center delegate UNUserNotificationCenter.current().delegate = self GeneratedPluginRegistrant.register(with: self) return super.application(application, didFinishLaunchingWithOptions: launchOptions) } // Add this method to handle foreground notifications override func application( _ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void ) { print("🔔 FULL didReceiveRemoteNotification CALLED") print("Full Payload: \(userInfo)") // Detailed logging of APS dictionary if let aps = userInfo["aps"] as? [String: Any] { print("APS Dictionary: \(aps)") print("Content Available: \(aps["content-available"] ?? "Not Found")") } // Explicit silent notification check if let aps = userInfo["aps"] as? [String: Any], let contentAvailable = aps["content-available"] as? Int, contentAvailable == 1 { print("✅ CONFIRMED SILENT NOTIFICATION") // Perform any background task here completionHandler(.newData) return } print("❌ Not a silent notification") completionHandler(.noData) } override func application( _ application: UIApplication, performFetchWithCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void ) { print("🔄 Background Fetch Initiated") // Perform any background fetch tasks completionHandler(.newData) } override func userNotificationCenter( _ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void ) { let userInfo = notification.request.content.userInfo print("**** willPresent notification ****") print("Full Notification Payload: \(userInfo)") // Explicitly log the aps dictionary if let aps = userInfo["aps"] as? [String: Any] { print("APS Dictionary: \(aps)") print("Content Available: \(aps["content-available"] ?? "Not Found")") } // Check for silent notification if let aps = userInfo["aps"] as? [String: Any], let contentAvailable = aps["content-available"] as? Int, contentAvailable == 1 { print("**** CONFIRMED SILENT NOTIFICATION IN FOREGROUND ****") completionHandler([]) return } // For non-silent notifications if #available(iOS 14.0, *) { completionHandler([.banner, .sound]) } else { completionHandler([.alert, .sound]) } } }
2
0
662
Dec ’24
Push payload is not present on notification tap
I am checking if the user taps on the firebase push notification and get the payload. override func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) { let userInfo = response.notification.request.content.userInfo os_log("notification tapped %{public}@", log: OSLog.push, type: .info, userInfo) handleNotificationPayload(userInfo as! [String: AnyObject]) setFlutterLinkClickedVariable() } My use case is in app terminated state when push notification is tapped, get the link from payload and navigate to corresponding screen based on the link. This is working when there is only one push notification. When there are multiple push notifications with different links in the payload, only the first notification I tap works. Rest of the notifications just launches the app and does not navigate because the link is not set. I am getting the link from the payload and invoking flutter code which sets the link in the user defaults (shared preferences) and when the app launches in the home screen it checks for this variable and navigates accordingly. func handleNotificationPayload(_ payload: [String: AnyObject]) { if let link = payload["link"] as? String { setFlutterLinkVariable(link) } } override func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) { os_log("app did receive remote notification %{public}@", log: OSLog.push, type: .info, userInfo) handleNotificationPayload(userInfo as! [String : AnyObject]) completionHandler(.newData) } Currently when there is only one push notification it works because the link is set from the above method. The click delegate is not calling. I did set the delegate in application(:didFinishLaunchingWithOptions). UNUserNotificationCenter.current().delegate = self application.registerForRemoteNotifications() How to solve this issue? Thanks.
2
0
719
Apr ’25
How can I keep my app up to date with the server without throttling
I am trying to build a chat app. I am using FCM to deliver messages to my app accompanied by some custom data like the new message_data, deleted message_id and so on; each message will need to run the app in the background to do some background processing and local database syncing. This continuous background processing is clearly not acceptable as APNs imposes a per-device limit on background push notifications . I am asking how can I push messages and actions payload without being throttled ?
2
0
419
Dec ’24
Failed to call ConversationManager.reportNewIncomingConversation in PushKit pushRegistry
Recently, I attempted to use LiveCommunicationKit to replace CallKit. The goal was to explore better features or integration. However, a major problem emerged. When the app is in the background or killed, it shows no notifications. This seriously impairs the app's communication functionality as notifications are vital for users to notice incoming calls. And it is working well when the app is in the foreground. When the app is in the background, when the push message received. the app get crashed with the following information: *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Killing app because it never posted an incoming call to the system after receiving a PushKit VoIP push.' Also, when I use CallKit instead of LiveCommunicationKit, the app works well in all cases. The code is here: LCK wrapper: class LCKWrapper : NSObject, ConversationManagerDelegate { var mgr: ConversationManager var lckDelegate: LCKDelegate var currentCallId: UUID @objc init(handler: LCKDelegate, appName: String, appIcon: UIImage) { self.lckDelegate = handler var iconData: Data? iconData = appIcon.pngData(); var cfg: ConversationManager.Configuration cfg = ConversationManager.Configuration(ringtoneName: "ringtone.m4a", iconTemplateImageData: iconData, maximumConversationGroups: 1, maximumConversationsPerConversationGroup: 1, includesConversationInRecents: false, supportsVideo: false, supportedHandleTypes: Set([Handle.Kind.phoneNumber])) self.mgr = ConversationManager(configuration: cfg) self.currentCallId = UUID() super.init() self.mgr.delegate = self } func reportIncomingCall(_ payload: [AnyHashable : Any], callerName: String) async { do { print("Prepare to report new incoming conversation") self.currentCallId = UUID() var update = Conversation.Update() let removeNumber = Handle(type: .generic, value: callerName, displayName: callerName) update.activeRemoteMembers = Set([removeNumber]) update.localMember = Handle(type: .generic, value: "", displayName: callerName); update.capabilities = [ .playingTones ]; try await self.mgr.reportNewIncomingConversation(uuid: self.currentCallId, update: update) print("report new incoming conversation Done") } catch { print("unknown error: \(error)") } } } And the PushKit wrapper: @available(iOS 17.4, *) @objc class PushKitWrapper : NSObject, PKPushRegistryDelegate { var pushKitHandler: PuskKitDelegate var lckHandler: LCKWrapper @objc init(handler: PuskKitDelegate, lckWrapper: LCKWrapper) { self.pushKitHandler = handler self.lckHandler = lckWrapper super.init() let mainQueue = DispatchQueue.main // Create a push registry object on the main queue let voipRegistry = PKPushRegistry(queue: mainQueue) // Set the registry's delegate to self voipRegistry.delegate = self // Set the push type to VoIP voipRegistry.desiredPushTypes = [.voIP] } func pushRegistry(_ registry: PKPushRegistry, didReceiveIncomingPushWith payload: PKPushPayload, for type: PKPushType) async { if (type != .voIP) { return; } await self.lckHandler.reportIncomingCall(payload.dictionaryPayload, callerName: "Tester") } }
2
0
418
Feb ’25
WKApplication.didBecomeActiveNotification not fired when Control Center (or other system overlay view) dismissed by system
https://forums.developer.apple.com/forums/thread/685317 Having read the above discussion, I can add there’s one problematic exception on watchOS to the rule that .didBecomeActiveNotification is fired when the Control Center or any other overlay (such as a long-look notification) is dismissed. It’s when it’s dismissed not by the user, but just allowed to dsimiss itself after a period (as determined by Settings > Wake Duration). This is a problem for any Watch workout app because when one of these overlays is covering the app, it’s considered by the system to be backgounded for purposes of applying the 15% avg CPU load over 60 seconds criteria for being terminated for using too much CPU in the background, so I have discovered. In the case of these overlays covering an app, the app never gets a .didEnterBackgroundNotification call to know that it should attempt to reduce its activity, when the user presses the Side Button to show the Control Center, which is by design, as I understand it. The app does get a .willResignActiveNotification when the Control Center covers it, but there is no corresponding .didBecomeActiveNotification when the system dismisses the Control Center after 2 minutes or so. So if the app reduces its actvity in an attempt to reduce CPU load when covered by the Control Center overlay, it has no way to know it has become active again, in the special case of the Control Center timing out and being dismissed by the system. What could be done to reduce the likelihood of the system terminating the app in this situation, and maintain the app's functionality and usability?
2
0
507
Oct ’24
Obtaining LiveActivities pushToStart token
I want to add Live Activities to my e-commerce app to show the estimated delivery ETA when an order is out for delivery, with the Live Activity initiated from the server. Issue 1: How can I consistently obtain a pushToStart token when a user logs in to my e-commerce app? Currently, I’m considering starting and ending a dummy Live Activity to retrieve the token. Is there a better way to trigger pushToStartTokenUpdates and send the token to my server? Issue 2: How do I properly invalidate the pushToStart token when a user logs out, ensuring the next user doesn’t inherit the same token? Ideally, I don't want the user to wait until the token is automatically invalidated before logging out.
2
0
571
Oct ’24
Rewrite `UNNotificationServiceExtension` sub class into Swift 6 async await notation
I'm trying to rewrite a Swift code to Swift 6 language mode and am stuck with this problem. How do I safely pass the bestAttemptContent and contentHandler to the Task? This is from the UNNotificationServiceExtension subclass. final class NotificationService: UNNotificationServiceExtension { var contentHandler: ((UNNotificationContent) -> Void)? var bestAttemptContent: UNMutableNotificationContent? var customNotificationTask: Task<Void, Error>? override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) { self.contentHandler = contentHandler bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent) guard let bestAttemptContent = bestAttemptContent else { invokeContentHandler(with: request.content) return } do { let notificationModel = try PushNotificationUserInfo(data: request.content.userInfo) guard let templatedImageUrl = notificationModel.templatedImageUrlString, let imageUrl = imageUrl(from: templatedImageUrl) else { invokeContentHandler(with: bestAttemptContent) return } setupCustomNotificationTask( imageUrl: imageUrl, bestAttemptContent: bestAttemptContent, contentHandler: contentHandler ) } catch { invokeContentHandler(with: bestAttemptContent) } } // More code private func downloadImageTask( imageUrl: URL, bestAttemptContent: UNMutableNotificationContent, contentHandler: @escaping (UNNotificationContent) -> Void ) { self.customNotificationTask = Task { let (location, _) = try await URLSession.shared.download(from: imageUrl) let desiredLocation = URL(fileURLWithPath: "\(location.path)\(imageUrl.lastPathComponent)") try FileManager.default.moveItem(at: location, to: desiredLocation) let attachment = try UNNotificationAttachment(identifier: imageUrl.absoluteString, url: desiredLocation, options: nil) bestAttemptContent.attachments = [attachment] contentHandler(bestAttemptContent) } } } I tried using the MainActor.run {}, but it just moved the error to that run function. The UNNotificationRequest is not sendable, and I don't think I can make it so. Wrap the setupCustomNotification in a Task will move the errors to the didReceive method. It seems like the consuming keyword will help here, but it leads to a compilation error, even with the latest Xcode (16.2). Any pointers?
2
1
439
Mar ’25