macosswiftuieventkit

Requesting EventKit access macOS SwiftUI


I am trying to request access to calendars in a SwiftUI MacOS app but it immediately denies it.

Below is some testable code highlighting what I want to achieve. Many thanks.

In my previous experience with requesting private information on MacOS a notification should appear instead of the popUp on iOS.

I'm still trying to figure out EventKit for SwiftUI so please excuse any mistakes.

struct ContentView: View {
    
    let eventStore = EKEventStore()
    
    var body: some View {
        
        Text("Test")
            .onAppear{
                checkCalendarAuthorizationStatus()
            }
        
    }
    
    
    func checkCalendarAuthorizationStatus() {

        
        switch EKEventStore.authorizationStatus(for: .event) {
        case .authorized:
            insertEvent(store: eventStore)
            case .denied:
                print("Access denied")
            case .notDetermined:
            // 3
                eventStore.requestAccess(to: .event, completion:
                  {(granted: Bool, error: Error?) -> Void in
                      if granted {
                        self.insertEvent(store: eventStore)
                      } else {
                            print("Access denied")
                      }
                })
            default:
                print("Case default")
        }
    }
    
    func insertEvent(store: EKEventStore) {
        // 1
        let calendars = store.calendars(for: .event)
            
        for calendar in calendars {
            // 2
            if calendar.title == "Calendar" {
                // 3
                let startDate = Date()
                // 2 hours
                let endDate = startDate.addingTimeInterval(2 * 60 * 60)
                    
                // 4
                let event = EKEvent(eventStore: store)
                event.calendar = calendar
                    
                event.title = "New Meeting"
                event.startDate = startDate
                event.endDate = endDate
                    
                // 5
                do {
                    try store.save(event, span: .thisEvent)
                }
                catch {
                   print("Error saving event in calendar")             }
                }
        }
    }
}

Solution

  • You should not check status, but request access with EKEventStore().requestAccess(... directly, as documented

    /**
        @method     requestAccessToEntityType:completion:
        @discussion Users are able to grant or deny access to event and reminder data on a per-app basis. To request access to
                    event and/or reminder data, call -requestAccessToEntityType:completion:. This will not block the app while
                    the user is being asked to grant or deny access.
     
                    Until access has been granted for an entity type, the event store will not contain any calendars for that
                    entity type, and any attempt to save will fail. The user will only be prompted the first time access is
                    requested; any subsequent instantiations of EKEventStore will use the existing permissions. When the user
                    taps to grant or deny access, the completion handler will be called on an arbitrary queue.
    */
    @available(macOS 10.9, *)
    open func requestAccess(to entityType: EKEntityType, completion: @escaping EKEventStoreRequestAccessCompletionHandler)
    

    so use the following

    func checkCalendarAuthorizationStatus() {
    
        eventStore.requestAccess(to: .event, completion:
          {(granted: Bool, error: Error?) -> Void in
              if granted {
                self.insertEvent(store: eventStore)
              } else {
                print("Access denied")
              }
        })
    }
    

    and make sure NSCalendarsUsageDescription description is added in Info.plist.