I am using CloudKit to store user data and want to get push notifications when the records are changed or new records are created. But it does not work...
I register for the subscriptions like this:
- (void) updateCloudSubscriptions {
NSPredicate *allPredicate = [NSPredicate predicateWithFormat:@"TRUEPREDICATE"];
CKSubscription *newOrUpdateSubscription = [[CKSubscription alloc]
initWithRecordType:kMyRecordType predicate:allPredicate options:
(CKSubscriptionOptionsFiresOnRecordCreation | CKSubscriptionOptionsFiresOnRecordUpdate)];
CKNotificationInfo *newOrUpdateNotificationInfo = [CKNotificationInfo new];
newOrUpdateNotificationInfo.shouldBadge = NO;
newOrUpdateNotificationInfo.shouldSendContentAvailable = YES;
newOrUpdateSubscription.notificationInfo = newOrUpdateNotificationInfo;
CKDatabase *publicDatabase = [[CKContainer containerWithIdentifier:kMyContainerID]
publicCloudDatabase];
[publicDatabase saveSubscription:newOrUpdateSubscription
completionHandler:^(CKSubscription *theSubscription, NSError *saveError) {
if (saveError){
//error handling
}
NSLog(@"Subscription created");
}];
}
This succeeds. On the CloudKit Dashboard the subscription is created correctly.
In my AppDelegate I now have the following:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
UIUserNotificationSettings *notificationSettings = [UIUserNotificationSettings settingsForTypes:
(UIUserNotificationTypeNone | UIUserNotificationTypeAlert |
UIUserNotificationTypeBadge | UIUserNotificationTypeSound) categories:nil];
[application registerUserNotificationSettings:notificationSettings];
[application registerForRemoteNotifications];
}
and these delegate methods implemented:
- (void)application:(UIApplication *)application
didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
NSLog(@"%@ with token = %@", NSStringFromSelector(_cmd), deviceToken);
}
- (void)application:(UIApplication *)application
didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
NSLog(@"%@ with error = %@", NSStringFromSelector(_cmd), error);
}
- (void)application:(UIApplication *)application
didReceiveRemoteNotification:(NSDictionary *)userInfo {
NSLog(@"%@", NSStringFromSelector(_cmd));
}
didRegisterForRemoteNotificationsWithDeviceToken
is called successfully with a token. But didReceiveRemoteNotification
is never called.
I tested this by changing values on the Mac version of my App and on the iPhone version. Both upload the changes but neither triggers a notification. I also tried changing the values directly on the dashboard but that did not cause notifications either.
What am I missing here?
If relevant: I am on OS X 10.10 with XCode 6.4
I activated apsd
logging but only get messages like this:
Jul 12 18:25:29 Mac.local apsd[44748]: APSMessageStore - Saving database.
Jul 12 18:25:29 Mac.local apsd[44748]: APSMessageStore - Destroying database.
Jul 12 18:25:29 Mac.local apsd[44748]: APSMessageStore - Closed database.
Jul 12 18:25:29 Mac.local apsd[44748]: APSMessageStore - Reopening database
Jul 12 18:25:29 Mac.local apsd[44748]: APSMessageStore - Initializing database on thread: <NSThread: 0x7f8f1bf80dd0>{number = 55, name = (null)}
Jul 12 18:25:29 Mac.local apsd[44748]: APSMessageStore - Enabling auto vacuum.
Jul 12 18:25:29 Mac.local apsd[44748]: APSMessageStore - Enabling WAL journal mode.
Jul 12 18:25:29 Mac.local apsd[44748]: APSMessageStore - Enabling Foreign Key support.
Your notification registration is correct for iOS 8, but on OS X you have to use registerForRemoteNotificationTypes:
method of NSApplication
and on iOS 7 the registerForRemoteNotificationTypes:
method of UIApplication
. Documentation:
An app must register with Apple Push Notification service (APNs) to receive remote notifications sent by the app’s push provider. In iOS 8 and later, registration has four stages:
- Register the notification types your app supports using registerUserNotificationSettings:.
- Register to receive push notifications via APNs by calling your app’s registerForRemoteNotifications method.
- Store the device token returned to the app delegate by the server for a successful registration, or handle registration failure gracefully.
- Forward the device token to the app’s push provider.
(In iOS 7, instead of the first two steps, you register by calling the registerForRemoteNotificationTypes: method of UIApplication, and in OS X by calling the registerForRemoteNotificationTypes: method of NSApplication.)
Also implement didReceiveRemoteNotification:fetchCompletionHandler:
instead of didReceiveRemoteNotification
:
Use this method to process incoming remote notifications for your app. Unlike the application:didReceiveRemoteNotification: method, which is called only when your app is running in the foreground, the system calls this method when your app is running in the foreground or background. In addition, if you enabled the remote notifications background mode, the system launches your app (or wakes it from the suspended state) and puts it in the background state when a remote notification arrives. However, the system does not automatically launch your app if the user has force-quit it. In that situation, the user must relaunch your app or restart the device before the system attempts to launch your app automatically again.
If you want the notifications to wake your app, make sure to edit Info.plist
and check the "Enable Background Modes" and "Remote notifications" check boxes:
Since you want a silent notification, per documentation, you should only send the "content-available" flag to 1, so that's correct. But there are other users that had problems with silent notifications and apparently, sending the "sound" property as an empty string did help (see this question), so you could try to set CKNotificationInfo.soundName
to an empty string.
The 2015 WWDC CloudKit Tips & Tricks video pointed out that if you want to send a silent push notification, you need to set the shouldSendContentAvailable
to true on your notificationInfo dictionary, like so:
let notificationInfo = CKNotificationInfo()
notificationInfo.shouldSendContentAvailable = true
subscription.notificationInfo = notificationInfo
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With