CKSubscription to creatorUserRecordID never arrives - ios

I create CKSubscription using the following code:
NSPredicate *predicate2 = [NSPredicate predicateWithFormat:#"(creatorUserRecordID == %#)", self.myRecordId];
CKSubscription *subscription2 = [[CKSubscription alloc]
initWithRecordType:#"Message"
predicate:predicate2
options:CKSubscriptionOptionsFiresOnRecordCreation];
where self.myRecordId is CKRecordID of the current logged user. I do this because I would like to receive notification when I create a new object (of type Message) but the problem is that notification never arrives. Anyone has idea why?

You should complete the missing steps described in the Quick Start Guide namely set the notification object, assign it to the subscription, and assign the subscription to the public database:
Please note the verification steps on the original source.

Related

EKEventStore will not return Exchange Calendar items by external or local identifier

I am using the EKEventStore API to save events to the default calendar using the following:
EKEventStore - saveEvent:span:commit:error:.
Once the event is saved, I store the externalID and localID in my database for future reference using the following:
externalID = [myEvent calendarItemExternalIdentifier]; and
localID = [myEvent eventIdentifier].
The problem I am having is that when I then go back to try and retrieve the event using the following:
[[eventStore calendarItemsWithExternalIdentifier:externalID] firstObject]
OR
[eventStore eventWithIdentifier:localID],
iOS is not able to find my event.
If I run the exact same code, but have my default calendar set to an iCloud calendar, however, everything works correctly.
But if the default calendar is an Exchange calendar, I am getting the following error message:
"Error getting calendar item with UUID [insert externalID here]: Error Domain=EKCADErrorDomain Code=1010 "(null)""
Has anyone encountered this issue?
I have had this code deployed for over 2 years now and users recently reported they weren't able to open appointments created on Exchange calendars. Not sure what changed or when, but I have tested this on iOS 10 and 11, and both have the issue.
Any insight would be greatly appreciated,
Sincerely,
~Arash
Unfortunately not... we were able to work around this issue by including an internal reference ID in the notes of the event. Then, if both the externalEventID and eventID failed to return the event, which is our issue with Exchange, then we fall back to use the start and end date in an EKEventSearchCallback to look for our event.
Basically, it ends up looking like this:
EKEventSearchCallback searchBlock = ^(EKEvent *event, BOOL *stop)
{
if([MyCustomClass event:event
notesMatchesKnownValueDict:knownValueDict])
{
foundEvent = event;
*stop = YES;
}
};
NSPredicate *predicate = [eventStore predicateForEventsWithStartDate:startDate
endDate:endDate
calendars:nil];
[eventStore enumerateEventsMatchingPredicate:predicate usingBlock:searchBlock];
Another solution might be waiting for the event to sync with Exchange. For example, I save the event and keep track of the ID assigned to it. Have a loop check every few seconds for a change. When the change happens, it's on the exchange server and you're good to reference that in your DB.
Try it out, let me know if it works!

cloudkit notifications for a specific field within a record

I have cloudkit notifications working. When someone changes the record, the subscribers are notified. My subscription definition looks like:
NSPredicate *searchConditions = [NSPredicate predicateWithFormat:#"%K = %#", CLOUDKIT_PUBLIC_ID_GUID, theCloudGUID];
int subscriptionOptions = CKSubscriptionOptionsFiresOnRecordUpdate | CKSubscriptionOptionsFiresOnRecordDeletion;
CKSubscription *publicSubscription = [[CKSubscription alloc] initWithRecordType:CLOUDKIT_RECORDNAME_PUBLIC_ID
predicate:searchConditions
options:subscriptionOptions];
CKNotificationInfo *notificationInfo = [CKNotificationInfo new];
notificationInfo.alertLocalizationKey = CLOUDKIT_NOTIFICATION_PUBLIC;
notificationInfo.shouldBadge = NO;
notificationInfo.alertBody = CLOUDKIT_NOTIFICATIONBODY_PUBLIC;
publicSubscription.notificationInfo = notificationInfo;
[publicDatabase saveSubscription:publicSubscription completionHandler:^(CKSubscription * _Nullable subscription, NSError * _Nullable error)
{
//error handling
}
The thing is, there are multiple fields in this record. I only want to alert the subscriber when one specific field changes.
When creating the subscription, is there a way to set the search predicate to detect a change in a specific field? I read through the various Predicate docs, but didn't see this specifically mentioned.
Or, when receiving the notification, is there a way to see which fields changed? In didReceiveRemoteNotification I tried:
CKQueryNotification *queryNotification = [CKQueryNotification notificationFromRemoteNotificationDictionary:userInfo];
But queryNotification.recordFields is null.
As a worst case, I have considered breaking the specific field out into it's own record, but then I have the overhead of maintaining more records tied together by a common GUID. I was hoping to keep this more compact.
Your question is aging a bit, so maybe you already figured this out, but using the desiredKeys property may help: https://developer.apple.com/documentation/cloudkit/cknotificationinfo/1514931-desiredkeys
If these notifications are silent pushes, you could look at the payload to see if certain keys changed and have your app react accordingly.
If these are push (visible-to-the-user) notifications, I don't think you can push based on the key changing per se. You could set an NSPredicate on your CKQuerySubscription if you were testing how the value changed (is it equal to this or not equal to that, etc.), but I'm not sure about it being triggered for any change at all.

How do you cancel a Nest ETA using Firebase on iOS?

According to the nest API docs:
"To cancel an eta, send estimated_arrival_window_begin = 0. Check that you're sending an integer (0) in this call, not a string ("0"), or the call will fail."
See https://developers.nest.com/documentation/cloud/eta-reference/
My code is based on the iOS NestDK sample which uses Firebase.
I set things up using the addSubscriptionToURL method as follows: ​
[[FirebaseManager sharedManager] addSubscriptionToURL:[NSString stringWithFormat:#"structures/%#/eta", structureId] withBlock:^(FDataSnapshot *snapshot) {}];
I can then make successful calls to set an eta window for a specific trip.
However, i can't seem to be able to cancel the eta for the same trip. If i just specify the trip_id and estimated_arrival_window_begin properties i get an error message complaining that the estimated_arrival_window_end field is missing.
NSMutableDictionary *values = [[NSMutableDictionary alloc] init];
[values setValue:[_tripId UUIDString] forKey:#"trip_id"];
[values setValue:[NSNumber numberWithInt:0] forKey:#"estimated_arrival_window_begin"];
[[FirebaseManager sharedManager] setValues:values forURL:[NSString stringWithFormat:#"structures/%#/eta", structureId]];
I tried also setting estimated_arrival_window_end to 0 but i then get an error message saying that the estimated_arrival_window_begin is in the past. It seems to be interpreting the 0 value as the beginning of time. Well some time in 1970 anyway!
What am i doing wrong here?!
Thanks!
Are you using a Nest account with virtual devices created with the Nest Home Simulator? There appears to be a bug using virtual devices versus real devices. Please try using a Nest account with real devices.

CloudKit subscription with "CONTAINS" predicate

I am trying to setup a CloudKit subscription based on testing membership in an array.
The code I'm using to create the subscription is as follows:
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"users CONTAINS %#", userID];
CKSubscription *itemSubscription = [[CKSubscription alloc] initWithRecordType:#"foo"
predicate:predicate
options:CKSubscriptionOptionsFiresOnRecordCreation|CKSubscriptionOptionsFiresOnRecordUpdate];
CKNotificationInfo *notificationInfo = [[CKNotificationInfo alloc] init];
[notificationInfo setAlertLocalizationKey:#"Record notification"];
[notificationInfo setShouldBadge:YES];
[itemSubscription setNotificationInfo:notificationInfo];
[database saveSubscription:itemSubscription completionHandler:^(CKSubscription *subscription, NSError *error) {
NSLog(#"Error: %#, Subscription: %#", error, subscription);
}];
The log shows that the subscription is created successfully, however when I test by adding or changing a record via the CloudKit admin console I never get a notification on device.
I am able to receive notifications for subscriptions with other kinds of predicates (I've tested with a simple true predicate, and one that tests equality against a string field), so I know I have the notification code setup correctly.
I've also verified that my predicate listed above works when used in a fetch records query, so I know the predicate is setup correctly for the record type I have in CloudKit.
Has anyone been able to get subscription notifications with a predicate that tests for membership in an array?
After playing around, I found that unless I set notificationInfo.alertbody the subscription never fired.
So try setting it to "Test" first, then after set it to "". I found it continued to work after I set it to a blank string (though I didn't try setting it blank to start with), and as a blank string it doesn't show a notification, but my handler still gets called, which was what I was after.
With iOS 8.1.1 / Xcode 6.1.1

CloudKit CKSubscription, subscriptionID

I am trying to study CloudKit and I saw this. https://github.com/ghvillasboas/CloudKitTest
After I have followed that instruction, I can run app and save, fetch data.
However, I saw this code
CKSubscription *subscription = [[CKSubscription alloc]
initWithRecordType:GVCloudKitRecordType predicate:[NSPredicate predicateWithFormat:#"TRUEPREDICATE"] subscriptionID:GVCloudKitSubscriptionId options:CKSubscriptionOptionsFiresOnRecordCreation];
GVCloudKitSubscriptionId = br.com.cocoaheads.cloudkittest.newHeroSubscription for that one. But, for me, how can I create subscriptionID? May I know from where I can register that or get that?
You can define your own subscriptionID. Just remember that ID so that you can also unregister. Create a logical ID. Something like "all" if you are using a true predicate.

Resources