【问题标题】:CloudKit didReceiveRemoteNotification not called on the Mac在 Mac 上未调用 CloudKit didReceiveRemoteNotification
【发布时间】:2015-11-14 19:14:18
【问题描述】:

我正在使用以下 CKNotification 信息,这似乎工作正常:

CKNotificationInfo *note = [[CKNotificationInfo alloc] init]; note.alertBody = @"Something Happened"; note.shouldBadge = NO; note.shouldSendContentAvailable = NO;

当 iOS 设备发生变化时,我的 Mac 应用会收到基于订阅的推送通知,其中包含此通知。但是,didReceiveRemoteNotification 从未被调用,因此我无法处理该事件。我需要能够刷新和获取新的更改。我该怎么做?

【问题讨论】:

  • 我遇到了同样的问题,当时我什至向苹果公司报告了这个问题。在某个时候,这个问题就消失了。不知道为什么。

标签: macos cocoa icloud cloudkit osx-yosemite


【解决方案1】:

调用registerForRemoteNotificationTypes: 并实现didRegisterForRemoteNotificationsWithDeviceToken: 应该是足够的代码,并且 App ID 应该包含 Push Notifications 服务。

我在跨平台 (iOS/OS X) 应用程序中使用 CloudKit 在设备之间同步收藏夹,如下所示:

// OS X specific code
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
    [NSApp registerForRemoteNotificationTypes:NSRemoteNotificationTypeNone];// silent push notification!
}

- (void)application:(NSApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
{
    [self.favCon handleCloudKitNotificationWithUserInfo:userInfo];
}

注意NSRemoteNotificationTypeNone 的用法,这意味着静默推送通知!这就是我在 FavController 类中设置 CloudKit 的方式:

- (void)getOrCreateFavZoneWithCompletionHandler:(successCompletionHandler)handler {

    // check if FavZone exists op
    __block int createZone = 0;
    CKFetchRecordZonesOperation *fetchRecZonesOp    = [[CKFetchRecordZonesOperation alloc] initWithRecordZoneIDs:@[[FavController favRecordZoneID]]];
    CKModifyRecordZonesOperation *saveRecZoneOp     = [[CKModifyRecordZonesOperation alloc] initWithRecordZonesToSave:nil recordZoneIDsToDelete:nil];
    fetchRecZonesOp.fetchRecordZonesCompletionBlock = ^(NSDictionary *recordZonesByZoneID, NSError *operationError) {
        if (recordZonesByZoneID.count == 0) {// zone doesn't exist
            createZone              = 1;
            CKRecordZone *favZone   = [[CKRecordZone alloc] initWithZoneName:UTXAFavZoneName];
            saveRecZoneOp.recordZonesToSave         = @[favZone];
            NSLog(@"Creating new Zone %@", favZone.zoneID.zoneName);
        } else {
            NSLog(@"Zone %@ already exists.", [FavController favRecordZoneID].zoneName);
        }
    };

    // create FavZone op
    saveRecZoneOp.modifyRecordZonesCompletionBlock  = ^(NSArray *savedRecordZones, NSArray *deletedRecordZoneIDs, NSError *operationError) {
        [self successCompletionHandler:(savedRecordZones.count == createZone) error:operationError informDelegate:YES handler:handler];
    };

    [saveRecZoneOp addDependency:fetchRecZonesOp];
    [[FavController favDatabase] addOperation:fetchRecZonesOp];
    [[FavController favDatabase] addOperation:saveRecZoneOp];
}

- (void)subscribeToFavChanges:(successCompletionHandler)handler {

    // get current subscription
    [[FavController favDatabase] fetchSubscriptionWithID:UTXAFavConCKSubscriptionID completionHandler:^(CKSubscription *subscription, NSError *error) {
        if (subscription) {
            NSLog(@"using existing subscription: %@", subscription);
            [self successCompletionHandler:YES error:nil informDelegate:NO handler:handler];
        } else {
            CKSubscription *sub = [[CKSubscription alloc] initWithZoneID:[FavController favRecordZoneID]
                                                          subscriptionID:UTXAFavConCKSubscriptionID
                                                                 options:0];// "You must specify 0 for this parameter. Zone subscriptions currently do not support any options."
            [[FavController favDatabase] saveSubscription:sub completionHandler:^(CKSubscription *subscription, NSError *error) {

                NSLog(@"created new subscription: %@ %@", subscription, error);
                [self successCompletionHandler:(error == nil) error:error informDelegate:YES handler:handler];
            }];
        }
    }];
}

只要我在一个设备上添加或删除记录,我就会在所有其他设备上收到通知,我会在 FavController 类中这样处理:

/// @abstract Handle push notifications sent by iCloud.
/// @discussion App delegates call this method when they receive a push notification through didReceiveRemoteNotification.
///          Currently, only airport favorites produce a PN, it is of type CKNotificationTypeRecordZone.
/// @param userInfo The userInfo dict tied to each push notification.
- (void)handleCloudKitNotificationWithUserInfo:(NSDictionary *)userInfo {

        [self recursivelyCheckForPreviousCloudKitNotifications];
}


- (void)recursivelyCheckForPreviousCloudKitNotifications {

    CKFetchNotificationChangesOperation *fetchOp    = [[CKFetchNotificationChangesOperation alloc] initWithPreviousServerChangeToken:_defCon.notificationChangeToken];
    __weak CKFetchNotificationChangesOperation *weakOp = fetchOp;

    fetchOp.notificationChangedBlock                = ^(CKNotification *notification) {
            [self handleNotification:notification];
    };

    fetchOp.fetchNotificationChangesCompletionBlock = ^( CKServerChangeToken *serverChangeToken, NSError *operationError) {
        NSLog(@"new notification change token: %@", serverChangeToken);
        _defCon.notificationChangeToken = serverChangeToken;
        if (weakOp.moreComing) {
            NSLog(@"more coming!!");
            [self recursivelyCheckForPreviousCloudKitNotifications];
        } else {
            NSLog(@"done handling notification changes.");

        }
    };
    [[FavController favContainer] addOperation:fetchOp];
}



- (void)handleNotification:(CKNotification *)notification {// withCompletionHandler:(successCompletionHandler)handler {

    if (notification.notificationType == CKNotificationTypeRecordZone) {// make sure we handle only zone changes

        CKRecordZoneNotification *noti = (CKRecordZoneNotification *)notification;

        if ([noti.recordZoneID.zoneName isEqualToString:[FavController favRecordZoneID].zoneName]) {
            // received an update for the fav zone
            [self queuedFavUpdateFromCloud];
        } else {
            // received an update for an unknown zone
            NSLog(@"WARNING: received an update for an unknown zone: %@", noti.recordZoneID.zoneName);
        }
    } else {
        NSLog(@"WARNING: received unknown notification: %@", notification);
    }
}

【讨论】:

  • 不。正如我所提到的,我说的是 CloudKit 和自动推送订阅通知。显然这是一个已知的错误。
  • 你有这个bug的参考吗?
  • 我已向 Apple 报告。这是 OS X 上所有版本的 CloudKit 的一个经过良好测试且可重现的错误。
  • 上述过程对我有用。如果由于错误而对您不起作用,那不是我的错,也没有理由拒绝投票。
  • 我从我的跨设备项目中添加了工作代码。您可以根据需要对我的答案投反对票,但此代码适用,是的,didReceiveRemoteNotification 被调用!
【解决方案2】:

好吧,我终于想通了。如果您使用 CKNotificationInfo 作为警报,除非您将 CKNotificationInfo.soundName 设置为空字符串,否则在 Mac 上不会调用 didReceiveRemoteNotification!这看起来只是 OS X(目前是 10.10 和 10.11)中的一个错误,但可以通过这个简单的更改来解决。

【讨论】:

  • 是的,我以前读过。请注意,我的示例代码是为静默推送通知而设计的。我会相应地编辑帖子。
  • 当然,但我的问题特别提到我正在使用“CKNotificationInfo”。顺便说一句,我也使用静默通知,只需为通知信息提供一个空标题。
  • 尽管将 soundName 设置为空字符串,但它仍然对我不起作用。我使用的是最新的 MacOS Catalina。
猜你喜欢
  • 2015-09-30
  • 1970-01-01
  • 1970-01-01
  • 2017-03-28
  • 2020-06-30
  • 1970-01-01
  • 2023-03-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多