I'm working on an app which needs to publish data to the user's calDAV calendar (iCloud or other). In order to do this, I need to detect if that source allows the creation of calendars and reminders.
EKSource doesn't offer much in terms of detecting anything, except provide you with the type of source (local, calDAV, Exchange...)
The only way I've thought of to detect if this is possible is to actually try to write a new Calendar and look at any error messages, like this:
-(BOOL)ekSourceWritesToEvents:(EKSource *)ekSource {
BOOL writesToEvents = NO;
//Try to write a calendar to it if it fails, return NO
//If you succeed, return YES, since this is uncommitted, no damage done
NSError *error = nil;
EKCalendar *testCalendar = [EKCalendar calendarForEntityType:EKEntityTypeEvent eventStore:self.eventStore];
testCalendar.title = @"TestCalendar";
testCalendar.source = ekSource;
BOOL result = [self.eventStore saveCalendar:testCalendar commit:NO error:&error];
if (result) {
NSLog(@"This Source can create calendars: %@",ekSource.title);
//Now check if one can create an event
EKEvent *newEvent = [EKEvent eventWithEventStore:self.eventStore];
newEvent.title = @"TestEvent";
newEvent.startDate = [NSDate date];
newEvent.endDate = [NSDate date];
newEvent.calendar = testCalendar;
NSError *eventCreateError = nil;
[self.eventStore saveEvent:newEvent span:EKSpanThisEvent commit:NO error:&eventCreateError];
if (eventCreateError) {
NSLog(@"Cannot Create EKEvent in test Calendar %@",eventCreateError.localizedDescription);
writesToEvents = NO;
} else {
writesToEvents = YES;
//Delete it even if uncommitted or it seems to get commited at some point
NSError *eventDeleteError = nil;
[self.eventStore removeEvent:newEvent span:EKSpanThisEvent commit:YES error:&eventDeleteError];
if (eventDeleteError) {
NSLog(@"Error removing event: %@",eventDeleteError.localizedDescription);
}
}
NSError *calendarDeleteError = nil;
[self.eventStore removeCalendar:testCalendar commit:YES error:&calendarDeleteError];
if (calendarDeleteError) {
NSLog(@"Error removing test calendar: %@",calendarDeleteError.localizedDescription);
}
} else {
NSLog(@"Cannot Save Calendar: %@.", error);
}
return writesToEvents;
}
I find this a clunky way of doing things... would there not be a way to detect this properly? I would rather the user know what to expect before selecting a destination Source which is why I want to do this before actually trying.
Thanks!
UPDATE: It seems checking for Calendar creation is not enough. You must also then test that the created calendar allows Writing... I'm investigating. Why could one create a calendar and not allow it to write is beyond me...
Update 2: Seems that even if we don't commit, the test calendar gets created somehow. So I've added code to remove the test event and Calendar.
UPDATE 3: More problems... checking for Calendar creation capability is not all... some services (Google) allow you to create events in your calendar, but not Calendars. You must create the Calendar using the Google site, or their API. On top of this, there seems to be a bug with Exchange servers when you try to create an EKEvent, it actually gives you an error that the calendar cannot create reminders. Weird.