How to add items to Reminders App in iOS 17.0?

191 Views Asked by At

I'm building an app that allows the user to add and create events in the Calendar native app for iPhone. One of the features I'm working on is also to allow the user to add and create items in the Reminder's native app of the iPhone.

From what I've read, the Calendar and Reminders app work with EventKit, and from the documentation, the process of each don't differ too much.

I'm using this code to request permission to access Reminders and the code I use to add the items to the app.

Any thoughts on why is it not working? Thanks in advance.

import Foundation
import EventKit

class EventModel {
    
    let eventStore  = EKEventStore()
    
    func requestAccessForReminders() {
        let status = EKEventStore.authorizationStatus(for: .reminder)
        if status == .authorized {
            print("EKEventStore access for Reminders already granted.")
        } else {
            eventStore.requestFullAccessToEvents { success, error in
                if success && error == nil {
                    print("EKEventStore access for Reminders has been granted.")
                } else {
                    print("EKEventStore access for Reminders request failed with error: \(error?.localizedDescription ?? "Unknown error")")
                }
            }
        }
    }
    
    func addEventToReminders(title: String, startHour: Int, startMinute: Int, duration: Int) -> Void {
        
        let newEvent = EKReminder(eventStore: self.eventStore)
        
        newEvent.title = title
        newEvent.calendar = self.eventStore.defaultCalendarForNewReminders()
        
        do {
            try eventStore.save(newEvent,
                                commit: true)
        } catch let error {
            print("Reminder failed with error \(error.localizedDescription)")
        }
    }
}

enter image description here

This is the information I have in the info.plist. (I know is the same message, but that shouldn't be the main cause am I right?)

2

There are 2 best solutions below

1
HangarRash On BEST ANSWER

Your primary issue is that you are requesting access to the calendar, not to reminders. Use requestFullAccessToReminders for iOS 17+ or requestAccess(to: .reminder) for iOS 16- instead of requestFullAccessToEvents.

Here's an updated version of your code that correctly requests access to reminders. This code handles iOS 17 as well as older versions of iOS. Obviously you need to call your requestAccessForReminders() function before trying to add any reminders. It might be better to provide a completion handler for requestAccessForReminders so you know when the request has completed.

class EventModel {
    let eventStore = EKEventStore()

    func requestAccessForReminders() {
        let status = EKEventStore.authorizationStatus(for: .reminder)
        switch status {
            case .notDetermined:
                func handleRequestCompletion(success: Bool, error: Error?) {
                    if let error {
                        print("Error trying to request access: \(error)")
                    } else if success {
                        print("User granted access")
                    } else {
                        print("User denied access")
                    }
                }

                if #available(iOS 17.0, *) {
                    eventStore.requestFullAccessToReminders { success, error in
                        handleRequestCompletion(success: success, error: error)
                    }
                } else {
                    eventStore.requestAccess(to: .reminder) { success, error in
                        handleRequestCompletion(success: success, error: error)
                    }
                }
            case .restricted:
                print("Restricted")
            case .denied:
                print("Denied") // Offer option to go to the app settings screen
            case .fullAccess, .authorized: // fullAccess is for iOS 17+. authorized is for iOS 16-
                print("Full access")
            case .writeOnly:
                print("Write-only access")
            @unknown default:
                print("Uh-oh, code is out-of-date")
        }
    }

    func addEventToReminders(title: String, startHour: Int, startMinute: Int, duration: Int) -> Void {
        let newEvent = EKReminder(eventStore: self.eventStore)

        newEvent.title = title
        newEvent.calendar = self.eventStore.defaultCalendarForNewReminders()

        do {
            try eventStore.save(newEvent, commit: true)
        } catch let error {
            print("Reminder failed with error \(error)")
        }
    }
}
1
benc On

If you use print to look at the behavior before save, you will probably find that:

print ("defaultCalendarForNewReminders",eventStore.defaultCalendarForNewReminders() as Any)

displays: defaultCalendarForNewReminders nil

You should be checking defaultCalendarForNewReminders, because it can be empty, but .calendar cannot be.

func defaultCalendarForNewReminders() -> EKCalendar?

https://developer.apple.com/documentation/eventkit/ekeventstore/1507543-defaultcalendarfornewreminders

var calendar: EKCalendar! { get set }

https://developer.apple.com/documentation/eventkit/ekcalendaritem/1507169-calendar

If you are working a clean simulator, the nil comes from checking from before the app was granted permissions. After permissions, you would see something like this:

defaultCalendarForNewReminders Optional(EKCalendar <0x60000212af80> {title = Reminders; type = Local; allowsModify = YES; color = #007AFFFF;})

Even if the Reminders.app was never run.