Reputation: 3246
I have created a CloudKit subscription to a specific class that fires a push notification on the object creation or update.
That code goes as following:
// Create the predicate
let predicate = NSPredicate(format: "recordId = %@", RECORD_ID)
// Create a subscription specifying the record type, predicate and notification options
let subscription = CKQuerySubscription(recordType: "Notes", predicate: predicate, options: [.firesOnRecordUpdate, .firesOnRecordCreation])
// Create a CloudKit notification object
let notificationInfo = CKNotificationInfo()
notificationInfo.shouldBadge = true
// Set the subscriptor's notification object to the new CloudKit notification object
subscription.notificationInfo = notificationInfo
// Save the subscription to the database
let publicDatabase = CKContainer.default().publicCloudDatabase
publicDatabase.save(subscription) { (subs, err) in
if let err = err {
print("Failed to save subscription:", err)
return
}
}
The subscription gets saved successfully in the server.
I wanted to create a silent notification, and I'm handling the notification (when received) as following:
import UserNotifications
// Register for push notifications
let notificationCenter = UNUserNotificationCenter.current()
notificationCenter.requestAuthorization(options: [.badge, .alert, .sound]) { (success, err) in
if let err = err {
print("Failed to request oauth for notifications:", err)
}
}
application.registerForRemoteNotifications()
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
print("didRegisterForRemoteNotificationsWithDeviceToken:", deviceToken)
}
func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
print("Failed to register notifications_ error:", error)
}
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
print("------------------------")
print("Receiving updates from the server")
// Convert the userInfo parameter to a CKNotification object
let cloudKitNotification = CKNotification(fromRemoteNotificationDictionary: userInfo)
// Get the body of the notification
let alertBody = cloudKitNotification.alertBody
print("alertBody:", alertBody ?? "")
// Get the new or modified record form the CKQueryNotification object
if cloudKitNotification.notificationType == CKNotificationType.query {
guard let queryNotification = cloudKitNotification as? CKQueryNotification else {
print("could not cast the query notification")
return
}
let recordId = queryNotification.recordID
print("recordId:", recordId ?? "")
}
}
Here's where the problem happens.
If I'm using the app and an update was sent to the server, my didReceiveRemoteNotification
fires and everything works properly, however if my app is in the background, my app_notification badge changes (increases by 1) when a push notification is received but the didReceiveRemoteNotification
doesn't fire.
My question is, how can I handle the push notification entry when it arrives?
I have set the Required background modes
in the Info.plis
file with App downloads content from the network
and App downloads content in response to push notifications
One more thing I noticed, If I set my notificationInfo.shouldBadge
to false I receive no push notifications.
Thanks for helping
Upvotes: 1
Views: 144
Reputation: 4187
Notifications are not guaranteed to arrive, especially if the user goes into airplane mode, loses connection, etc. And, even if you do receive the notice, when your app is running, you can't execute any processing. This means you must assume every time you start the app that there are notifications still waiting for processing (those that you received while you weren't in the app as well as those that you never received any push notice for, for whatever reason).
So, When you start the app, you need to issue a CKFetchNotificationsChangesOperation
and look for new notifications that you haven't processed yet.
You create the CKFetchNotificationChangesOperation
operation, and set the notificationChangedBlock
. That block will be called once for each notification pulled from the server. You can evaluate if it's already marked as "read" yet. If not, then handle it however you normally do in didReceiveRemoteNotification
.
Optionally, you can also set code in the fetchNotificationChangesCompletionBlock
that will fire once, at the very end of the operation, after all notifications have been fetched from the server.
Upvotes: 1