iosiphoneswiftpermissionscalendar

EKEventStore requestAccess() is failing to display the user prompt in iOS 9


I've run into a strange case with requesting Calendar access in iOS 9. The logic works fine on all iOS 10 devices.

In our case, we've added a button on a toolbar that the user taps to add an Event to their Calendar.

So, we don't check for permission to access the calendar until the first time the user taps the "Add to Calendar" button. Like this:

 @IBAction func addToCalendarPressed(_ sender: UIBarButtonItem) {
    eventStore.requestAccess(to: .event, completion: { (granted, error) in
        if (granted) && (error == nil) {
           // Present the EKEventEditViewController
        } else {
           // Do something else (show an alert)
        }
    })
 }

In iOS 10, the app displays the prompt for Calendar access as you'd expect. In iOS 9.x, the prompt doesn't display, the completion handler fires immediately, and granted returns false.

Worse, even though the "Calendar permission" check appears to have completed, you can't go into Settings and manually enable Calendar access. As far as the device is concerned, the app never made the permission check, so the app never appears under Settings > Privacy > Calendar.

I've tried to move the check into viewWillAppear or viewDidLoad instead of waiting for the user to tap the button, and it still doesn't work. I've pulled some sample apps with the event check and they work in iOS 9. I just haven't been able to figure out why the prompt fails in this instance.

The app also checks for location (but not on this screen), and those work correctly in iOS 9.


Solution

  • We found the issue. Somehow our project didn't have CFBundleDisplayName in the info.plist. At a later point in development, opening the project in Xcode 8 added the property, but left the name blank.

    Both the Calendar permission and Photos permission prompts for iOS 9 use that value when displaying the application name in the permission prompt.

    The fix was to simply set $(PRODUCT_NAME) for CFBundleDisplayName in our info.plist.