CKSubscription not working

732 views Asked by At

I am creating my two CKSubscriptions in my App Delegate's didFinishLaunchingWithOptions method as such.

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // Override point for customization after application launch.

    UIUserNotificationSettings *notificationSettings = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert categories:nil];
    [[UIApplication sharedApplication] registerUserNotificationSettings:notificationSettings];
    [[UIApplication sharedApplication] registerForRemoteNotifications];

    _myContainer = [CKContainer containerWithIdentifier:@"iCloud.com.isaranjha.Copyfeed"];
    _privateDatabase = [_myContainer privateCloudDatabase];

    [_privateDatabase fetchSubscriptionWithID:@"subscription" completionHandler:^(CKSubscription *subscription, NSError *error){

        if (subscription) {

        } else {

            NSPredicate *predicate = [NSPredicate predicateWithValue:YES];
            CKSubscription *subscription = [[CKSubscription alloc] initWithRecordType:@"Strings" predicate:predicate subscriptionID:@"subscription" options:CKSubscriptionOptionsFiresOnRecordCreation | CKSubscriptionOptionsFiresOnRecordDeletion | CKSubscriptionOptionsFiresOnRecordUpdate];
            CKNotificationInfo *notificationInfo = [CKNotificationInfo new];
            notificationInfo.alertBody = @"";
            notificationInfo.shouldSendContentAvailable = YES;
            subscription.notificationInfo = notificationInfo;

            [_privateDatabase saveSubscription:subscription completionHandler:^(CKSubscription *subscription, NSError *error) {

            }];

        }

    }];


    [_privateDatabase fetchSubscriptionWithID:@"subscription1" completionHandler:^(CKSubscription *subscription, NSError *error){

        if (subscription) {

        } else {

            NSPredicate *predicate1 = [NSPredicate predicateWithValue:YES];
            CKSubscription *subscription1 = [[CKSubscription alloc] initWithRecordType:@"Images" predicate:predicate1 subscriptionID:@"subscription1" options:CKSubscriptionOptionsFiresOnRecordCreation | CKSubscriptionOptionsFiresOnRecordDeletion | CKSubscriptionOptionsFiresOnRecordUpdate];
            CKNotificationInfo *notificationInfo1 = [CKNotificationInfo new];
            notificationInfo1.shouldSendContentAvailable = YES;
            notificationInfo1.alertBody = @"";
            subscription1.notificationInfo = notificationInfo1;
            [_privateDatabase saveSubscription:subscription1 completionHandler:^(CKSubscription *subscription, NSError *error) {

            }];

        }

    }];

    ViewController *view = [[ViewController alloc] init];

    UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:view];
    self.window.rootViewController = navController;

    return YES;
}

Those are created successfully, as when I log out NSError, it returns null and every time I open the app after that, it is able to fetch them correctly. However, when a record is created or deleted, on one device, say an iPhone, the notification doesn't fire (or it is not being properly received) on the other device, say a Mac. So here is how I am listening for the notifications on my Mac.

- (void)application:(NSApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {

    NSLog(@"CKSubscription received.");

    CKQueryNotification *cloudKitNotification = [CKQueryNotification notificationFromRemoteNotificationDictionary:userInfo];

    [[NSNotificationCenter defaultCenter] postNotificationName:@"CloudKitUpdated" object:nil userInfo:@{@"ckNotification" : cloudKitNotification}];
}

That NSLog unfortunately never fires.

1

There are 1 answers

1
Edwin Vermeer On BEST ANSWER

You have an empty alertbody

notificationInfo1.alertBody = @"";

With that you won't receive push notifications when your app is not active. When you manually activate your app you will be able to query for the notifications using CKFetchNotificationChangesOperation. Here is a snippet of how I use it in EVCloudKitDao:

public func fetchChangeNotifications(skipRecordID: CKRecordID?, inserted:(recordID:String, item: EVCloudKitDataObject) -> Void, updated:(recordID: String, item: EVCloudKitDataObject) -> Void, deleted:(recordId: String) -> Void, completed:()-> Void) {
    var defaults = NSUserDefaults.standardUserDefaults()
    var array: [NSObject] = [NSObject]()
    var operation = CKFetchNotificationChangesOperation(previousServerChangeToken: self.previousChangeToken)
    operation.notificationChangedBlock = { notification in
        if notification.notificationType == .Query  {
            if var queryNotification = notification as? CKQueryNotification {
                array.append(notification.notificationID)
                if skipRecordID != nil && skipRecordID?.recordName != queryNotification.recordID.recordName {
                    if queryNotification.queryNotificationReason == .RecordDeleted {
                        deleted(recordId: queryNotification.recordID.recordName)
                    } else {
                        EVCloudKitDao.publicDB.getItem(queryNotification.recordID.recordName, completionHandler: { item in
                            EVLog("getItem: recordType = \(EVReflection.swiftStringFromClass(item)), with the keys and values:")
                            EVReflection.logObject(item)
                            if queryNotification.queryNotificationReason == .RecordCreated {
                                inserted(recordID: queryNotification.recordID.recordName, item: item)
                            } else if queryNotification.queryNotificationReason == .RecordUpdated {
                                updated(recordID: queryNotification.recordID.recordName, item: item)
                            }
                        }, errorHandler: { error in
                            EVLog("ERROR: getItem for change notification.\n\(error.description)")
                        })
                    }
                }
            }
        }
    }
    operation.fetchNotificationChangesCompletionBlock = { changetoken, error in
        var op = CKMarkNotificationsReadOperation(notificationIDsToMarkRead: array)
        op.start()
        EVLog("changetoken = \(changetoken)")
        self.previousChangeToken = changetoken

        if operation.moreComing  {
            self.fetchChangeNotifications(skipRecordID, inserted: inserted, updated: updated, deleted: deleted, completed:completed)
        } else {
            completed()
        }
    }
    operation.start()
}

when your app is active, then you should receive the notifications in the application didReceiveRemoteNotification.