How to Get Calendar Permissions with EventKit in Swift in macOS App - eventkit

I'm trying to add a calendar event to the macOS calendar from a Mac app I'm developing with Swift 5 in Xcode 11.2.1.
For starters, I have the Calendar entitlement checked in the App Sandbox.
I'm trying to prompt for permissions like this:
import EventKit
#IBAction func clickAddToCalendar(_ sender: NSButton){
let eventStore = EKEventStore()
eventStore.requestAccess(to: .event){ granted, error in
print(granted) // returns false
print("----")
print(error) // returns nil
}
}
...but granted is false every time and I never see a popup to grant permission. Is prompting for access like this necessary on macOS? It would seem so, because when I attempt to add a calendar event directly like this:
let event = EKEvent(eventStore: eventStore)
event.title = "My Event"
event.startDate = Date()
event.endDate = Date()
event.calendar = eventStore.defaultCalendarForNewEvents
do {
try eventStore.save(event, span: .thisEvent)
} catch let error as NSError {
print(error)
}
...I get an error:
serviceName = "com.apple.CalendarAgent.database"; ... returned error NSCocoaErrorDomain(134070) with userInfo dictionary { Problem = "request failed, insufficient permission" }
Has anyone does this that could give me some pointers? Thank you!

Do you have an info.plist item for Privacy - Calendars Usage Description?
required for EventKit see https://developer.apple.com/documentation/eventkit/accessing_the_event_store

Related

Badge is not displaying OSX cocoa swift

I am trying to display badge count in MacOS Ventura for my application, Here is my code
NSApplication.shared.dockTile.showsApplicationBadge = true
NSApplication.shared.dockTile.badgeLabel = "2"
NSApplication.shared.dockTile.display()
I also requested for notification allow
//create the notificationCenter
let center = UNUserNotificationCenter.current()
center.delegate = self
// set the type as sound or badge
center.requestAuthorization(options: [.sound,.alert,.badge]) { (granted, error) in
if granted {
print("Notification Enable Successfully")
}else{
print(error.debugDescription) // prints "Notifications are not allowed for this application"
}
}
but it is always going into error part, I don't know what's issue there.
I also checked in Notification settings in System preference, It's showing only alert there. There is no badge setting there.
How to add badge setting in notification setting? Here is the screenshot
Any help would be appreciated.

iOS Dev cannot delete Calendar event using eventIdentifier programmatically

I can save event into Calendar user
do {
try self.store.save(event, span: .thisEvent, commit: true)
self.addedEventId = event.eventIdentifier
print("\(self.addedEventId) has been added")
}
catch let error as NSError {
print("\(error.localizedDescription), userInfo: \(error.userInfo)")
}
it saved the event, and print eventIdentifier
61211649-CED1-4C74-A140-843AE0C38F44:8B7BDC14DD804F069D455E7B8F3534EF0
but when I try to delete the saved event using
if let eventToRemove = self.store.event(withIdentifier: self.addedEventId)
{
do {
try self.store.remove(eventToRemove, span: .thisEvent)
print("\(self.addedEventId) removed")
} catch let error as NSError {
print("\(error.userInfo)")
}
}
Seems I cannot find the event using eventIdentifier, the error I have from the console reads
Error getting event with identifier 61211649-CED1-4C74-A140-843AE0C38F44:8B7BDC14DD804F069D455E7B8F3534EF0: Error Domain=EKCADErrorDomain Code=1010 "(null)
After half day research, I finally found a way around is instead of using eventIdentifier, using calenderItemIdentifier

Error Editing Google Sheets Swift

I am trying to edit google sheets from within swift. I used the original Quickstart tutorial by google, but since that is for reading a spreadsheet, I had to slightly edit it for writing to a spreadsheet.
//Signing in as normal from the Google Quickstart
//This function is the one I edited, to write to the spreadsheet
func listMajors() {
output.text = "Getting sheet data..."
let spreadsheetId = "**********************"
let range = "Sheet 1!A2"
let valueRange = GTLRSheets_ValueRange.init()
valueRange.values = [["Hello" as Any]]
let query = GTLRSheetsQuery_SpreadsheetsValuesUpdate.query(withObject: valueRange, spreadsheetId: spreadsheetId, range: range)
query.valueInputOption = "USER_ENTERED"
service.executeQuery(query, delegate: self, didFinish: #selector(displayResultWithTicket(ticket:finishedWithObject:error:)))
}
func displayResultWithTicket(ticket: GTLRServiceTicket, finishedWithObject result : GTLRSheets_ValueRange, error : NSError?) {
if let error = error {
showAlert(title: "Error", message: error.localizedDescription)
return
}
print(result)
}
It seemed to work fine for the reading spreadsheet, but it is not working for writing to spreadsheet. The app launches, then i get an error alert with this:
Sorry to add solution in objective-C, but i think you will be able to manage conversion
I just have the same problem today.
The solution is simple, when initializing the GIDSignIn
// Configure Google Sign-in.
GIDSignIn* signIn = [GIDSignIn sharedInstance];
signIn.delegate = self;
signIn.uiDelegate = self;
signIn.scopes = [NSArray arrayWithObjects:kGTLRAuthScopeSheetsSpreadsheets, nil];
[signIn signInSilently];
Note the scope value. In the quickStart tutorial, kGTLRAuthScopeSheetsSpreadsheetsReadonly is used.
Romain

CNContact(s) created locally are not synced to iCloud account

Recently some of our users were complaining about contacts not syncing to their iCloud account. It was working in iOS 8 and mysteriously stopped in one of the updates in iOS 9. With iOS 10 around the corner I thought it might be linked to deprecation of AddressBook.framework to Contacts.framework. However, even moving to new Contacts.framework it didn't fix the problem.
There are no error logs on console of the device and neither of the frameworks generate any errors when contacts are being created/updated on the device.
Contacts are visible and available on the device just not syncing to iCloud and other devices attached to the iCloud account.
After a lot of debugging what I was able to isolate the issue to imageData property. Contacts which had imageData populated were not synced and the few which had no images were synced. This lead me to look at the code for imageData. Turns out I had been using UIImagePNGRepresentation to convert UIImage to NSData for imageData. Moving to UIImageJPEGRepresentation fixed the issue. The day was saved and iCloud accounts are synced.
Thank you Apple for not documenting this change. (it might be the image size even that is not documented)
CNContact(s) created locally are not synced to Third party application.
I have crated contacts in iphone contacts page.Those contacts are not synching inside my application.I have used below method to fetch contacs from my contacts framework.
There are no error logs on console of the device and neither of the frameworks generate any errors when contacts are being created/updated on the device.
Contacts are visible and available on the device just not syncing to my app.I have given permission to my application to access my contacts.
#available(iOS 10.0, *)
func retrieveContacts(_ completion: (_ success: Bool, _ contacts: [ContactEntry]?) -> Void) {
var contacts = [ContactEntry]()
do {
let contactsFetchRequest = CNContactFetchRequest(keysToFetch: [CNContactGivenNameKey as CNKeyDescriptor, CNContactFamilyNameKey as CNKeyDescriptor, CNContactImageDataKey as CNKeyDescriptor, CNContactImageDataAvailableKey as CNKeyDescriptor, CNContactPhoneNumbersKey as CNKeyDescriptor, CNContactEmailAddressesKey as CNKeyDescriptor])
try contactStore.enumerateContacts(with: contactsFetchRequest, usingBlock: { (cnContact, error) in
if let contact = ContactEntry(cnContact: cnContact) {
contacts.append(contact)
print(contact,contacts.count)
}
})
completion(true, contacts)
} catch {
completion(false, nil)
}
let keysToFetch = [CNContactFormatter.descriptorForRequiredKeys(for: .fullName),CNContactPhoneNumbersKey] as [Any]
let fetchRequest = CNContactFetchRequest( keysToFetch: keysToFetch as! [CNKeyDescriptor])
var contacts1 = [CNContact]()
if #available(iOS 10.0, *) {
fetchRequest.mutableObjects = false
} else {
// Fallback on earlier versions
}
fetchRequest.unifyResults = true
fetchRequest.sortOrder = .userDefault
let contactStoreID = CNContactStore().defaultContainerIdentifier()
print("\(contactStoreID)")
do {
try CNContactStore().enumerateContacts(with: fetchRequest) { (contact, stop) -> Void in
contacts1.append(contact)
print(contact)
}
} catch let e as NSError {
print(e.localizedDescription)
}

Error Getting Default Calendar For New Events - Swift

I encountered an issue trying to create a new event on iOS's Calendar application while using Swift.
This is what I have so far:
func addToCal(){
let eventStore = EKEventStore()
eventStore.requestAccessToEntityType(EKEntityTypeReminder) {
(granted: Bool, err: NSError!) in
if granted && !err {
var event:EKEvent = EKEvent(eventStore: eventStore)
event.title = self.eventTitle!.text
event.startDate = self.eventData.startDateObj
event.endDate = self.eventData.endDateObj
event.calendar = eventStore.defaultCalendarForNewEvents
eventStore.saveEvent(event, span: EKSpanThisEvent, error: nil)
println("Saved Event")
}
}
This is the error that I'm getting:
Error getting default calendar for new events: Error Domain=EKCADErrorDomain Code=1013 "The operation couldn’t be completed. (EKCADErrorDomain error 1013.)"
I checked my syntax and I'm pretty sure I got it right, so can anyone help me figure out where I'm going wrong?
Additional Information
iOS 8 Beta 5
Xcode 6 Beta 5
Issue occurs on iPad Mini w/ Retina Display (real device)
Update
Changing EKEntityTypeReminder to EKEntityTypeEvent (Sorry, my mistake) actually doesn't produce an error, but now the event doesn't even show up in Calendar. I checked the outputs of granted and err and I see false and nil, respectively.
I think your main problem was that you weren't committing the new event to be saved. The following code is what I use, and the prime difference is that my code includes a commit and allows my error to be changed from 'nil' if there is one. The conditional at the end just prints any reports of save errors or save successes to the Debug Area.
let eventStore = EKEventStore()
let event = EKEvent(eventStore: eventStore)
event.title = "Your Event Title Here" // Sets event's title
event.startDate = NSDate() // Sets event's start date
event.endDate = event.startDate.dateByAddingTimeInterval(20000) // Sets event's end date
event.calendar = eventStore.defaultCalendarForNewEvents // Selects default calendar
var saveError : NSError? = nil // Initially sets errors to nil
eventStore.saveEvent(event, span: EKSpanThisEvent, commit: true, error: &saveError) // Commits changes and allows saveEvent to change error from nil
//// Following checks for errors and prints result to Debug Area ////
if saveError != nil {
println("Saving event to Calendar failed with error: \(saveError!)")
} else {
println("Successfully saved '\(event.title)' to '\(event.calendar.title)' calendar.")
}
Hope this helps!
-Gorowski
Once access has been granted, you need to set the 'eventStore':
eventStore.requestAccess(to: .event) { (granted, error) in
if (granted) && (error == nil) {
//Set event store now access granted
eventStore = EKEventStore()
//Save calendar event here...
} else {
}
}