I send APNs notifications to my devices with the CloudKit dashboard. I test with two devices;
Device with Silent Push Working Successfully:
iOS version 16.5.1
(c), Model iPhone Xs
Silent Push Failed Device:
iOS version 15.3.1
, Model iPhone Xr
Normal alert notifications work successfully on both devices. But I can't see any log in my project even though silent push is sent successfully on one device.
What I've Checked:
-
content-available
is set to1
. -
My app is not in kill state, it is in foreground or pending in the background.
-
When I send simple notifications, I can see logs in my swift project and notifications on physical devices without any problem.
-
No, my certificate has not expired and if there was a problem with it, I would not be able to see the normal notifications.
-
My phone is not in power saving mode and the “Background App Refresh” option is turned on in the app's settings.
-
Both devices in charging state.
-
App capabilities: Background Modes is enabled with
Remote Notifications
,Background Fetch
,Background Processing
.
CloudKit Dashboard After Sending Silent Push:
My AppDelegate Class In Swift Project:
import SwiftUI
import UIKit
import UserNotifications
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) { granted, error in
if granted {
DispatchQueue.main.async {
UIApplication.shared.registerForRemoteNotifications()
}
}
}
return true
}
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
let tokenParts = deviceToken.map { data in String(format: "%02.2hhx", data) }
let token = tokenParts.joined()
print("Device Token: \(token)")
}
func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
print("Failed to register: \(error)")
}
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
logInfo("Received Push Notification: \(userInfo)")
if let aps = userInfo["aps"] as? [String: AnyObject], aps["content-available"] as? Int == 1 {
logInfo("This is a silent push notification")
//DO SOME WORK
completionHandler(.newData)
}
completionHandler(.newData)
}
}
Delivery of silent pushes to the app is under the complete discretion of the system. While you may think the conditions are ideal, the system could still have a reason to not pass the notification to your app.
If you watch the Console output and search for your Bundle ID, you should be able to see the moment the system has made a decision about the push.
Also, I see you are sending a completely silent push with Priority 10. Silent pushes with no visible content should be sent at Priority 5. In any case as the push type is Background, APNs will still consider this a low priority push. Low priority pushes may not be sent to the device immediately, and could be held back until a regular/high priority push is going to be sent.
Argun Tekant / DTS Engineer / Core Technologies