CloudKit 推送通知 didReceiveRemoteNotification 从未调用过

CloudKit Push Notifications didReceiveRemoteNotification never called

我正在使用 CloudKit 来存储用户数据,并希望在记录更改或创建新记录时获得推送通知。但它不起作用...

我这样注册订阅

- (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");
    }];
}

这就成功了。在 CloudKit 仪表板上,订阅已正确创建

在我的 AppDelegate 中,我现在有以下内容:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

    UIUserNotificationSettings *notificationSettings = [UIUserNotificationSettings settingsForTypes:
        (UIUserNotificationTypeNone | UIUserNotificationTypeAlert |
        UIUserNotificationTypeBadge | UIUserNotificationTypeSound) categories:nil];
    [application registerUserNotificationSettings:notificationSettings];
    [application registerForRemoteNotifications];
}

并实现了这些委托方法:

- (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使用令牌成功调用。但是 didReceiveRemoteNotification 永远不会被调用。

我通过更改我的应用程序 Mac 版本和 iPhone 版本的值对此进行了测试。两者都上传了更改,但都没有触发通知。我还尝试直接在仪表板上更改值,但这也没有引起通知。

我在这里错过了什么?

如果相关:我在 OS X 10.10 和 XCode 6.4

我激活了 apsd 日志记录,但只收到这样的消息:

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.

2015 WWDC CloudKit Tips & Tricks video 指出,如果你想发送静默推送通知,你需要在你的 notificationInfo 字典中将 shouldSendContentAvailable 设置为 true,像这样:

let notificationInfo = CKNotificationInfo()
notificationInfo.shouldSendContentAvailable = true
subscription.notificationInfo = notificationInfo

您的通知注册对于 iOS 8 是正确的,但是在 OS X 上您必须使用 NSApplicationregisterForRemoteNotificationTypes: 方法和 iOS 7 UIApplicationregisterForRemoteNotificationTypes: 方法。 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:

  1. Register the notification types your app supports using registerUserNotificationSettings:.
  2. Register to receive push notifications via APNs by calling your app’s registerForRemoteNotifications method.
  3. Store the device token returned to the app delegate by the server for a successful registration, or handle registration failure gracefully.
  4. 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.)

同时实现 didReceiveRemoteNotification:fetchCompletionHandler: 而不是 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.

如果您希望通知唤醒您的应用,请确保编辑 Info.plist 并选中 "Enable Background Modes" 和 "Remote notifications" 复选框:

由于您需要静默通知,根据文档,您应该只将 "content-available" 标志发送到 1,这是正确的。但是还有其他用户在静默通知方面遇到问题,显然,将 "sound" 属性 作为空字符串发送确实有所帮助 (see this question),因此您可以尝试设置 CKNotificationInfo.soundName 为空字符串。