CloudKit didReceiveRemoteNotification not called on the Mac

谁说我不能喝 提交于 2019-12-12 10:06:55

问题


I am using the following CKNotification Info and this seems to work fine:

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

When something changes on an iOS device, my Mac app receives a Push notification based on a subscription with this notification. However, didReceiveRemoteNotification is never called so I can't process the event. I need to be able to refresh and fetch new changes. How do I do that?


回答1:


Calling registerForRemoteNotificationTypes: and implementing didRegisterForRemoteNotificationsWithDeviceToken: should be enough code, and the App ID should include the Push Notifications service.

I'm using CloudKit in a cross-platform (iOS/OS X) app to synchronize favorites between devices like so:

// 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];
}

Note the usage of NSRemoteNotificationTypeNone which means silent push notification! This is how I set up CloudKit in the FavController class:

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

As soon as I add or remove a record on one device, I'll get a notification on all other device, which I handle like so in the FavController class:

/// @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);
    }
}



回答2:


Okay I've finally figured it out. If you use a CKNotificationInfo for your alerts, didReceiveRemoteNotification will NOT be called on the Mac until and unless you set CKNotificationInfo.soundName to an empty string! This looks like a bug only in OS X (10.10 & 10.11 so far) but can be worked around by this simple change.



来源:https://stackoverflow.com/questions/32130206/cloudkit-didreceiveremotenotification-not-called-on-the-mac

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!