Handling Access to Calendars in iOS 6

I had to laugh at my last post. I went on hiatus in August 2010 and now I’m back, in 2012. I’ve been busy working on Skedi Family Calendar, which aggregates calendar data from different vendors such as Google Calendar, Microsoft Exchange, etc.

Anyway, the latest release of iOS (6.0) isolates a user’s calendars and blocks access by default. This presented a problem for us at Rodax Software because we also support earlier versions of iOS (i.e., 4 and 5) and we wanted to avoid using conditional compilation.

In iOS 6, access to the calendars is controlled through the EKEventStore class. In the past, we’d call a alloc/init and that was it.  This is unchanged; however, now we need to request permission and if granted, we can access the users calendars and events. Note: This request can only be performed once, which I’ll cover later.

 _store = [[EKEventStore alloc] init];

So, if we need to support earlier versions of iOS, how can we avoid using ugly preprocessor macros? Simple, use the power of Objective-C’s dynamic typing. In iOS 6, the method to request access in EKEventStore is requestAccessToEntityType. Hence, we need to determine if it’s available.

if([_store respondsToSelector:@selector(requestAccessToEntityType:completion:)]) {
	//invoke requestAccessToEntityType...
}

If the statement is true, request access:

[_store requestAccessToEntityType:EKEntityTypeEvent
                       completion:^(BOOL granted, NSError *error) {
 //Handle the response here…
//Note: If you prompt the user, make sure to call the main thread

}];

Since you can only request access once, you’ll need to test for the current authorization status first. We decided to create our own status flags that correspond with Event Kit’s then call authorizationStatus.

/// \brief Proxy for EKAuthorizationStatus in iOS 6
enum SKEKAuthorizationStatus {
    SKEKAuthorizationStatusNotDetermined = 0,
    SKEKAuthorizationStatusRestricted,
    SKEKAuthorizationStatusDenied,
    SKEKAuthorizationStatusAuthorized
};

/// \brief Helper method checks the authorization
/// \return If running in iOS 6 or higher returns the EKAuthorizationStatus; otherwise, returns SKEKAuthorizationStatusAuthorized
- (enum SKEKAuthorizationStatus) authorizationStatus {
    if ([[EKEventStore class] respondsToSelector: @selector(authorizationStatusForEntityType:)]) {
        return [EKEventStore authorizationStatusForEntityType:EKEntityTypeEvent];
    }
    else {
        return SKEKAuthorizationStatusAuthorized;
    }
}

If calendar access was denied before (SKEKAuthorizationStatusDenied), then we prompt the user to enable access by tapping Settings > Privacy > Calendars > Skedi. If permission is undetermined (SKEKAuthorizationStatusNotDetermined), then we instantiate the EKEventStore and request access. If previously granted access, we can safely alloc and init without a care.

So, I hope this helps anyone who is currently working on adapting their Event Kit code for iOS 6. Let me know if you have any feedback.

Advertisements
Handling Access to Calendars in iOS 6