Hi everyone,
We're experiencing an issue with our Flutter app that uses PushKit, CallKit, and Janus for handling VoIP calls. Everything works fine when the app is in the foreground, but when the app is in the background or completely closed (terminated state), the behavior is inconsistent:
Sometimes, incoming calls are received as expected.
Other times, the app does nothing, and the call is not delivered at all.
Upon checking the console logs, we noticed that our app is being canceled (terminated by the system), which seems to be the reason why calls are not coming through. This happens randomly, making it difficult to reproduce consistently.
Additional Details:
The app is configured to handle VoIP notifications correctly.
We are using PushKit to wake up the app and trigger CallKit for the incoming call UI.
When the app is active, calls are handled correctly via Janus WebRTC signaling.
We have verified that background modes for VoIP are enabled in the Info.plist.
We suspect that iOS may be aggressively killing the app in the background, preventing incoming call notifications from reaching it.
Questions:
Has anyone experienced similar behavior with PushKit + CallKit on recent iOS versions?
Could iOS be terminating the app due to background execution policies?
Are there recommended best practices to ensure reliable delivery of VoIP notifications when the app is closed?
Any insights or suggestions would be greatly appreciated!
Thanks!
Addional Information:
this is the cancellation information at console: Received incoming message on topic hiperme.app at priority 10
por omisión 17:10:18.462084-0300 dasd CANCELED: com.apple.pushLaunch.hiperme.app:E8BACD at priority 10
Notifications
RSS for tagLearn about the technical aspects of notification delivery on device, including notification types, priorities, and notification center management.
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Activity
Hello, I'm from Microsoft team maintaining push notification api behind Teams platform.
We are experiencing strange and short error spikes towards APNS that seem to mostly correlate worldwide. We checked the networking and push request code but could not find what could be causing this. These error spikes are all timeouts or connection resets (by remote host, ie. APNS servers) and seem to come and go randomly:
Would it be possible to check this for outages or some other metrics on your side or investigate why would it happen? Since it's worldwide it seems unlikely it's something broken on our side. We are using the standard APNS http2 endpoint with modern support for all RFC features (so everything should work normally).
Mind you, our api might be in a unique position because of the volume of notifications (in the billions per day).
I'm sending push notifications to a notification extension, and within the extension setting the threadIdentifier to be the same.
But I'm observing inconsistent grouping behaviour, and behaviour that changes over time.
The general iPhone settings are to display notifications as a Stack, and the app settings are to show on lock screen, notification center and banners and the notification grouping is set to by app (changing it to automatic doesn't affect the behaviour below).
Pushes are displayed on the lock screen grouped together, then if the device is roused and the screen swiped down to reveal the notification center then they are still grouped.
So far so good.
If the iphone is active then the notifications appear at the top of the screen, one by one, but in this case if there is a swipe down to reveal the notification center then the notifications are not grouped when displayed, but shown individually.
But then if one waits a few minutes and then displays the notification center for a 2nd time, sometimes now they will be grouped, but sometimes not.
Why are they not (always) being displayed as grouped in the notification center?
I'm strugling about the way how to code notifications for my weather aplication. I use data from my server that receives weather changing values from my own weather station and want to notify user of my app when eg strong wind will **** or temperature go under eg 3℃ etc.
The weather station has 8 sensors so there is sometimes a lot of data changing in particular minute that i set to parse data from server and notify user about it. But the notifications only works only when app is on and couple minutes after locking display.
So please what could i use strategy for the app to works even when the app sleeps ?
Topic:
App & System Services
SubTopic:
Notifications
Tags:
APNS
Notification Center
User Notifications
I am trying to issue the "start" APNs push notification to start a live activity for my iOS app. The notification appears to send correctly, there is no error message, but the live activity never appears for any of my users (users are in TestFlight).
In addition to issuing the APNs commands from my server, I have also tried using the CloudKit Push Notification Console to manually generate a "start" notification. It submits correctly but the live activity never starts.
I have also checked the Console app to watch the device logs and see if iOS is rejecting/throttling the live activity but I don't see any activity related to the start message at all.
Here are some details:
App bundle ID: `com.penzu.moodmoji`
APNs topic: `com.penzu.moodmoji.push-type.liveactivity`
APNs push type: `liveactivity`
Recent apns-id: `7b633309-b7fd-4163-b620-776efa04f315`
APNs payload:
{
"aps": {
"timestamp": 1742651625,
"event": "start",
"content-state": {
"totalDays": 7,
"currentDay": 2,
"progress": 0.29,
"status": "ACTIVE",
"reportReady": false
},
"attributes-type": "GoalActivityAttributes",
"attributes": {
"totalDays": 7,
"currentDay": 2,
"progress": 0.29,
"status": "ACTIVE",
"reportReady": false
},
"alert": {
"title": "It's day 2!",
"body": "Don't forget to record every time you feel anxious today."
}
}
}
I can confirm that LiveActivities started by the iOS app with ActivityKit work correctly, and the app does appear to be receiving pushToStartTokenUpdates:
struct GoalActivityAttributes: ActivityAttributes, Sendable {
struct ContentState: Codable & Hashable, Sendable {
let totalDays: Int
let currentDay: Int
let progress: Double
let status: String
let reportReady: Bool
}
let goal: SimpleGoal
}
for await nextStartToken in Activity<GoalActivityAttributes>.pushToStartTokenUpdates {
// send nextStartToken to server...
}
The app I'm testing with is in TestFlight, using the production APNs environment.
There's plenty of articles out there about programatically grouping push notifications. However I have tried setting the thread-id in the push payload when sending a push, or setting the threadIdentifier for a received push in a notification service extension to be the same for several pushes.
But if within the iPhone Settings / Notifications the user selects to display pushes as List and turns off Notification Grouping, then each notification resulting from the push appears on its own separately.
Is there something other than thread-id/threadidentifier that is used to programmatically group them? If not then whats the point of these as grouping and display is actually under the control of user.
I have three apps with a very low user rate, so it's easier to compare.
In all three apps, when I send a notification to APNs, over two-thirds receive a "Stored - Device Offline" status, but only one or two notifications are delivered afterward.
No message has been sent after that.
The total number of recipients is 89;
26 were delivered to the device, and 62 were stored in APNs.
One was delivered from storage, and one was discarded.
All app users are located in the same region, and mobile internet or Wi-Fi is available everywhere.
I can't believe that so many iPhone users aren't getting connected to APNs to receive the stored message. Or are event not connected.
Or are there any other reasons why a notification cant be transmitted. (User beahaviour, time of not using the app or something else?)
Dear Apple!
During WWDC24 you announced that ONE_TIME_CHARGE notification is available on the sandbox environment and will be available "it will be available in production later this year" - it's March 2025 and there is still no production release of this feature.
Could you share some timeline and plans for when we can expect that feature deployed to production?
Thanks in advance!
I am trying to retrieve delivered notifications using UNUserNotificationCenter.getDeliveredNotifications(completionHandler:), but I have encountered an issue:
Notifications triggered by UNTimeIntervalNotificationTrigger or UNCalendarNotificationTrigger appear in the delivered list.
However, notifications triggered by UNLocationNotificationTrigger do not appear in the list.
Here is the code I use to fetch delivered notifications:
UNUserNotificationCenter.current().getDeliveredNotifications { notifications in
for notification in notifications {
print("Received notification: \(notification.request.identifier)")
}
}
The notification is scheduled as follows:
let center = UNUserNotificationCenter.current()
let content = UNMutableNotificationContent()
content.title = "Test Notification"
content.body = "This is a location-based notification."
content.sound = .default
let coordinate = CLLocationCoordinate2D(latitude: 37.7749, longitude: -122.4194) // Example coordinates
let region = CLCircularRegion(center: coordinate, radius: 100, identifier: "TestRegion")
region.notifyOnEntry = true
region.notifyOnExit = false
let trigger = UNLocationNotificationTrigger(region: region, repeats: false)
let request = UNNotificationRequest(identifier: "LocationTest", content: content, trigger: trigger)
center.add(request) { error in
if let error = error {
print("Error adding notification: \(error.localizedDescription)")
}
}
Why does getDeliveredNotifications not return notifications that were triggered using UNLocationNotificationTrigger?
How can I retrieve such notifications after they have been delivered?
Hello,
We are trying to implement Actionable Notifications on iOS via Remote Notifications.
According to Apple’s official documentation (Declaring Your Actionable Notification Types),
it is recommended to register notification categories at launch time.
However, in our use case, the number of buttons and their actions in the Actionable Notification are determined at the time of the Remote Notification request.
This means that we cannot predefine the categories at app launch but need to dynamically configure them based on the payload of the Remote Notification.
Our Approach
We are considering setting aps.mutable-content = 1 and using Notification Service Extension to modify the categoryIdentifier dynamically.
Below is the JSON payload we plan to use for Remote Notifications:
{
"aps": {
"alert": {
"title": "New Message Received!",
"body": "Check out the details."
},
"category": "DYNAMIC_CATEGORY",
"mutable-content": 1
},
"categoryData": {
"id": "DYNAMIC_CATEGORY",
"actions": [
{
"id": "REPLY_ACTION",
"title": "Reply",
"options": ["foreground"]
},
{
"id": "DELETE_ACTION",
"title": "Delete",
"options": ["destructive"]
}
]
}
}
Questions:
Can we dynamically configure Actionable Notifications based on the Remote Notification payload?
If we set categoryIdentifier in Notification Service Extension’s didReceive(_:withContentHandler:), will users still see the correct action buttons even if the app is terminated?
What is the recommended approach to dynamically configure Actionable Notifications at the time of receiving the Remote Notification, rather than at app launch?
This is in an iOS Simulator running iOS 18.2
I send a start live activity push notification from the Push Notifications Console on icloud.developer.apple.com. When checking the console.log output it seems to receive the message, yet the activity does not appear in the dynamic island. (the app is backgrounded when I test this)
Can anyone tell me why it's not showing? Starting the same activity from within the app using Swift code works fine.
Here is the console.app output:
default 11:01:59.060954+0100 apsd <APSConnectionServer: 0x104207b80; development/com.apple.aps.sessioncore.PushNotifications.dev/liveactivitiesd 0>: Sending push to client. UUID: (null)
default 11:01:59.061012+0100 apsd Dispatching high priority message on server: <APSConnectionServer: 0x104207b80; development/com.apple.aps.sessioncore.PushNotifications.dev/liveactivitiesd 0>
default 11:01:59.061770+0100 apsd Looking up connection on peer: 4304b50 found <APSConnectionServer: 0x104207b80; development/com.apple.aps.sessioncore.PushNotifications.dev/liveactivitiesd 0>
default 11:01:59.062283+0100 liveactivitiesd APSXPCDeliverMessageEvent: Created APSIncomingMessage. UUID: (null)
default 11:01:59.062642+0100 liveactivitiesd <APSConnection: 0x600003d18000> Delivering message from apsd: <APSIncomingMessage: 0x600000c2e9a0> 2897852514 com.****.****.push-type.liveactivity
default 11:01:59.062763+0100 liveactivitiesd <APSConnection: 0x600003d18000> Delivering message from apsd. UUID: (null)
default 11:01:59.063374+0100 liveactivitiesd <APSConnection: 0x600003d18000> making delegate (<SessionPushNotifications.APSPushConnection: 0x600000227460>) calls to deliver message 2897852514 {
aps = {
alert = {
"loc-key" = "recording_started_message";
"title-loc-key" = "recording_started_title";
};
attributes = {
isRecording = 1;
};
"attributes-type" = SWAutomaticTripRecorderActivityAttributes;
"content-state" = {
distance = 0;
};
event = start;
timestamp = 1742374701;
};
} for topic com.****.****test.push-type.liveactivity
default 11:01:59.063440+0100 liveactivitiesd <APSConnection: 0x600003d18000> calling <SessionPushNotifications.APSPushConnection: 0x600000227460> connection:didReceiveIncomingMessage:
default 11:01:59.063740+0100 liveactivitiesd Acquiring keep-alive with reason: Received message
default 11:01:59.063785+0100 liveactivitiesd Keep-alive reasons: ["Received message": 1]
default 11:01:59.063803+0100 liveactivitiesd <APSConnection: 0x600003d18000> returned from <SessionPushNotifications.APSPushConnection: 0x600000227460> connection:didReceiveIncomingMessage:
default 11:01:59.063883+0100 liveactivitiesd <APSConnection: 0x600003d18000> responding with an ack for message with guid E19D7D04-12A0-4F1B-B33C-F6BF57EE2EFF
default 11:01:59.063921+0100 liveactivitiesd <APSConnection: 0x600003d18000> responding with an ack. UUID: (null)
default 11:01:59.063996+0100 apsd Looking up connection on peer: 4304b50 found <APSConnectionServer: 0x104207b80; development/com.apple.aps.sessioncore.PushNotifications.dev/liveactivitiesd 0>
default 11:01:59.064019+0100 apsd <APSUserCourier 0x100f052a0 development 0> informed that <APSConnectionServer: 0x104207b80; development/com.apple.aps.sessioncore.PushNotifications.dev/liveactivitiesd 0> acknowledges incoming message with guid E19D7D04-12A0-4F1B-B33C-F6BF57EE2EFF tracingUUID (null)
default 11:01:59.064063+0100 liveactivitiesd Received message: topic: Topic(unsuffixed: "com.****.****test"); channelID: nil; token: Optional(128 bytes); eventType: start(SessionPushNotifications.IncomingMessage.EventType.StartParameters(attributesType: "SWAutomaticTripRecorderActivityAttributes", attributesData: 20 bytes, inputs: [])) for environment: development
default 11:01:59.064198+0100 liveactivitiesd Received push event for com.****.****test::pushToStart
default 11:01:59.064232+0100 liveactivitiesd Adding push-to-start budget for com.****.****test::pushToStart
default 11:01:59.064273+0100 liveactivitiesd Acquiring keep-alive with reason: Database
default 11:01:59.064296+0100 liveactivitiesd Keep-alive reasons: ["Database": 1, "Received message": 1]
default 11:01:59.064313+0100 liveactivitiesd Acquiring keep-alive with reason: Database
default 11:01:59.064330+0100 liveactivitiesd Keep-alive reasons: ["Database": 2, "Received message": 1]
default 11:01:59.064342+0100 liveactivitiesd Reduced budget for com.****.****test::pushToStart to: 9
default 11:01:59.064358+0100 liveactivitiesd Topic com.****.****test.push-type.liveactivity has remaining budget for pushToStart of 9
default 11:01:59.064369+0100 liveactivitiesd Topic com.****.****test.push-type.liveactivity has not used any budget for activity
default 11:01:59.064436+0100 liveactivitiesd Scheduling wake to re-evaluate push subscription budgets at 2025-03-19 11:01:59 +0000
default 11:01:59.064547+0100 liveactivitiesd Earliest nonwaking date from task "Push server budget timeout expiration": 2025-03-19T12:01:59+01:00, finalWakeTarget: 2025-03-19T12:01:59+01:00 3599.999696
default 11:01:59.064593+0100 liveactivitiesd Earliest waking date from task "Push server budget timeout expiration": 2025-03-19T12:01:59+01:00, finalWakeTarget: 2025-03-19T12:01:59+01:00 3599.999651
default 11:01:59.064620+0100 liveactivitiesd Scheduling nonwaking task for: 2025-03-19T12:01:59+01:00 in 3599.999622s
default 11:01:59.064659+0100 liveactivitiesd Scheduling waking task for: 2025-03-19T12:01:59+01:00 in 3599.999584s
default 11:01:59.064671+0100 liveactivitiesd Acquiring keep-alive with reason: wake scheduling
default 11:01:59.064692+0100 liveactivitiesd Keep-alive reasons: ["Database": 2, "Received message": 1, "wake scheduling": 1]
default 11:01:59.064734+0100 liveactivitiesd Scheduling waking task for adjusted date: 2025-03-19T12:01:59+01:00 in 3599.999508s
default 11:01:59.064768+0100 liveactivitiesd xpc_activity_register: com.apple.sessionkit.wake, criteria: dictionary
default 11:01:59.064843+0100 liveactivitiesd Received pushToStart notification for com.****.****test::pushToStart
default 11:01:59.064955+0100 liveactivitiesd Keep-alive reasons: ["Database": 2, "Received message": 1]
default 11:01:59.064979+0100 liveactivitiesd Publishing event: timestamp: 2025-03-19 08:58:21 +0000; activityIdentifier: F432AB2F-1799-4437-B54B-6D9D70A0B260; eventType: start(SessionPushNotifications.PushEvent.EventType.ActivityStartParameters(attributesType: "SWAutomaticTripRecorderActivityAttributes", attributesData: 20 bytes, contentSourceRequests: [ActivityKit.ActivityContentSource.Request.push(request: ActivityKit.PushActivityContentSource.Request.push, target: ProcessDescriptor.Request("com.****.****test")), ActivityKit.ActivityContentSource.Request.process(target: ProcessDescriptor.Request("com.****.****test"))]))
I have integrated a Notification Service Extension in my app to handle rich push notifications with images. The issue occurs on iOS 15 and iOS 18 devices—while the text content of the notification shows, the image is not displayed. However, the rich push notification works fine on other iOS versions (e.g. iOS 16, iOS 17)
I’ve tried the following steps:
Verified App Groups are the same for both the main app and the extension.
Checked the "mutable-content" flag in the notification payload.
Added a print statement in the NotificationService.swift to check if it’s running. It doesn’t appear in the Xcode logs.
I’ve tried using Attach to Process in Xcode, but nothing happens.
The app is installed on a real device, and I’m testing with push notifications when the app is in the background.
Topic:
App & System Services
SubTopic:
Notifications
I have been watching the following moment from wwdc (Design dynamic Live Activities):
https://developer.apple.com/videos/play/wwdc2023/10194/?time=728
It suggest that you should 'tick' between multiple live activities of your app:
When you want to show multiple sessions for your app going on at once, consider ticking between the display of them to continue to give users an eye on everything that’s going on.
How can I tick between them? More specifically how can I do that when my app is in the background?
Hello,
I am developing a calling service using CallKit and VOIP push.
I have occasionally encountered a strange issue.
The issue is that VOIP permanently fails to receive calls.
I was previously informed that even if the device is blocked, it can receive calls again after 24 hours.
Also, when I checked the device logic, it complied with the policy requirements set by Apple, including correctly calling CallKit's reportNewIncomingCall method.
Once the issue occurs, no matter how many times I try, VOIP does not receive calls, and neither a device reboot nor checking the Device Console Log shows any logs related to CallKit or VOIP.
I suspect this might be an issue with the VOIP token, and I believe that the only way to get a new one is to reinstall the app. Is that correct?
Of course, after reinstalling, it works fine again, but this is very inconvenient. I don't think this is the right solution.
Is there anyone who can share their insights on this issue?
Thank you.
Hey there my application allows users to have video calls with each other using Agora. I have successfully set up incoming call functionality on Android but on iOS I am struggling to get the call ui to appear when the app is not running/in background/locked.
To my knowledge this is because there is much stricter security on iOS which is limiting me from calling this. When i initially set it up it worked at first when the app was in the background but I think I was failing to report the call to call kit in time and now it's not working.
I'm not sure if I need access to this entitlement:
com.apple.developer.pushkit.unrestricted-voip
Which i believe is only for the big boys or if I make sure I'm reporting the call to call kit fast enough that I won't encounter this issue and it will consistently work in the background.
Hello Everyone,
I somehow missed to renew the APNS Certificate,
I am new to Apple Ecosystem, I can not see the expired or any Certificates under
Certificates, Identifiers & Profiles
Can anyone help me with this!
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?
self.pushRegistry = [[PKPushRegistry alloc] initWithQueue:dispatch_get_main_queue()];
self.pushRegistry.delegate = self;
self.pushRegistry.desiredPushTypes = [NSSet setWithObject:PKPushTypeVoIP];
//处理接收到的VoIP推送
(void)pushRegistry:(PKPushRegistry *)registry didReceiveIncomingPushWithPayload:(PKPushPayload *)payload forType:(PKPushType)type withCompletionHandler:(void(^)(void))completion
then we send message from our server or from apple's cloud service: https://icloud.developer.apple.com/dashboard/notifications website services:
when app is in foreground,withCompletionHandler wil be called correctly,but when app is in background or has killed ,withCompletionHandler not be called!!!
the background fetch、voice over ip is checked in signing & capabilities tabs
why?why?why?why?why?why?why?why?why?
when I implementation the UNUserNotificationCenterDelegate
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
var status = ""
if (UIApplication.shared.applicationState == .active) {
status = "active"
} else if (UIApplication.shared.applicationState == .background) {
status = "background"
} else if (UIApplication.shared.applicationState == .inactive) {
status = "inactive"
}
completionHandler()
}
I find that UIApplication.shared.applicationState == .background this case can not execute when application is in background。
why applicationState is inactive not background?
In the main app, is there a way to distinguish whether the application:didFinishLaunchingWithOptions: method is triggered by the user manually clicking the app icon, or whether it is automatically triggered by the system after Live Activities receives a remote message notification?