Empty EKEventStore calendar list after authentication - swift

I would like to grab the names of my calendars on my Mac. I have 1 that's listed as "On My Mac", another (Birthdays) under "Other", and 4 that are pulled in from Google Calendar.
let eventStore = EKEventStore()
eventStore.requestAccess(to: EKEntityType.event) { (accessGranted, error) in
if (accessGranted) {
let calendars = eventStore.calendars(for: .event)
print(calendars)
}
}
The goal is to determine how many days remain until the next event across all selected calendars.
Using the above code, I'm getting back an empty array. How can I access these calendars?

Related

Cloudkit notifications only when certain parts of record are changed

I am creating an app that has profiles stored as records on CloudKit. When one user adds another user. The Requester is added to the requestees. Request list. (this is where I would like a notification with the requesters name going to the requestee).
Then once the requestee accepts they are added to the requesters friendlist property on CloudKit and visa-versa.
However all the documentation I have found only shows how to send a notification anytime the CKRecord/Profile is updated in anyway. Which is what I currently have implemented but too many notifications are sent (I.e. when they change their profile name, avatar, etc...) Here is my current implementation:
func subscribeToNotifications(profile: OKGNProfile) async {
let predicate = NSPredicate(format: "name == %#", profile.name)
let subscription = CKQuerySubscription(recordType: "OKGNProfile", predicate: predicate, subscriptionID: "friendRequestAddedToDatabase", options: .firesOnRecordUpdate)
let notification = CKSubscription.NotificationInfo()
notification.title = "Friend Request"
notification.alertBody = "Open friend feed in app to see new friend request from \(profile.name)!"
notification.soundName = "default"
subscription.notificationInfo = notification
CKContainer.default().publicCloudDatabase.save(subscription) { returnedSub, returnedError in
if let error = returnedError {
print(error)
} else {
print("✅ sucessfully subscribed to notifications")
}
}
}

EventKit. How can I get videoconference url from EKEvent

I have an event that has a meet or zoom link. However, I can't find a way to get the link of type https://meet.google.com/.... An example:
let calendars = eventStore.calendars(for: .event)
var events: [EKEvent] = []
for calendar in calendars {
let oneMonthAfter = Date(timeIntervalSinceNow: 30*24*3600)
let predicate = eventStore.predicateForEvents(withStart: Date(), end: oneMonthAfter, calendars: [calendar])
let collection = eventStore.events(matching: predicate)
events.append(contentsOf: collection)
}
let event = events.first! // This event has a meet link associated but I can't get the link
EventKit has a class named EKVirtualConferenceURLDescriptor (more info here). However, the documentation isn't good and only talks about creating a new one, not how we can get it from an existing event.

Swift OSX CNContact.organizationName crash in High Sierra

My OSX app allows the user to select a contact from their contacts list and loads the details into a Customer record. I am using CNContactPicker to retrieve a contact into a CNContact record. One of the fields I need to retrieve is organizationName. This works perfectly in OS's prior to High Sierra, but upon upgrading to High Sierra it will crash. All other CNContact fields can be retrieved with no issue (e.g. names, email, address etc). I do have permissions requested in my info.plist file.
It makes no difference if the Contact does/does not have an Organization Name.
Not much to show in terms of code:
// This fails on 1st line - any reference to organizationName causes failure
if (contact.organizationName != "") {
self.name = contact.organizationName
}
// This works
if (contact.givenName != "") {
self.name = contact.givenName
}
// This works
if (contact.contactType == CNContactType.organization) {
// Do something
}
The actual error is: [General] A property was not requested when contact was fetched.
I would like to know what has changed in the OS to cause this error, and if there is a solution or workaround please.
I submitted a bug report with Apple and received the following response which fixes my issue. Essentially, even though I have retrieved a Contact that the user selected, I need to do a CNContactFetchRequest to fetch this specific contact again (using the identifier) with keys specified (e.g. organisation).
Here is their exact response:
If you want to make sure organizationName is available, execute a CNFetchRequest for a contact with the same identifier (as returned from CNContactPicker delegate method) and provide a set of keys to fetch containing CNContactOrganizationName.
Here is the code:
var validContacts: [CNContact] = []
let contactStore = CNContactStore()
do {
// Specify the key fields that you want to be fetched.
// Note: if you didn't specify your specific field request. your app will crash
let fetchRequest = CNContactFetchRequest(keysToFetch: [CNContactOrganizationNameKey as CNKeyDescriptor])
fetchRequest.predicate = CNContact.predicateForContacts(withIdentifiers: [contact.identifier])
try contactStore.enumerateContacts(with: fetchRequest, usingBlock: { (contact, error) -> Void in
validContacts.append(contact)
})
for validContact in validContacts {
// Do something with your contact, there should be only one.
}
} catch let e as NSError {
print(e)
}

Add Reminder List programmatically

I'm building an application that interacts with the macOS Reminder App. I'm trying to create a new Reminder list into which I later can import reminders.
This is what I have so far:
func setCalendar(_ type: EKEntityType) {
let eventStore = EKEventStore()
let newCalendar = EKCalendar(for: type, eventStore: eventStore)
newCalendar.title="newcal"
print("Cal: " + newCalendar.title)
try? eventStore.saveCalendar(newCalendar, commit: true)
}
However, there is no reminder list being created.
The problem is that you have omitted to specify the new calendar's .source. You cannot create a calendar of any kind (event or reminder) without doing that.

CKSubscription error iOS10

My subscriptions were working properly with iOS 9, but since I updated, I have a very odd error. I have two subscription methods that are equal, except for the fields they manage. Here is the code:
let meetingSubscriptionPredicate = Predicate(format: "Users CONTAINS %#", (id?.recordName)!)
let meetingSubscription = CKQuerySubscription(recordType: "Meetings", predicate: meetingSubscriptionPredicate, options: .firesOnRecordCreation)
let notification = CKNotificationInfo()
notification.alertBody = "Meeting Created!"
notification.shouldBadge = true
notification.accessibilityPerformEscape()
meetingSubscription.notificationInfo = notification
database.save(meetingSubscription) { (result, error) -> Void in
if error != nil {
print(error!.localizedDescription)
}
}
let universitiesSubscriptionPredicate = Predicate(format: "Name = %#", self.UniversityTextField.text!)
let universitiesSubscription = CKQuerySubscription(recordType: "Universities", predicate: universitiesSubscriptionPredicate, options: .firesOnRecordCreation)
let universitiesNotification = CKNotificationInfo()
universitiesNotification.alertBody = "Your university is now on Meet'em!"
universitiesNotification.shouldBadge = true
universitiesNotification.accessibilityPerformEscape()
universitiesSubscription.notificationInfo = universitiesNotification
database.save(universitiesSubscription, completionHandler: { (saved, error) in
if error != nil {
print(error!.localizedDescription)
}
else {
print("University subscription created")
}
})
The odd thing is that the Meeting subscription is saved, and the University's subscription is not. I've double checked the names and they are all right at the Dashboard. Besides that, I'm not getting any notification on my phone when supposed to...
Found elsewhere online that you can try to reset your development environment. In my case, the predicate I was trying to use was not set to queryable. This is ticked where you define your record type. The reason it worked one day and not another is possibly due to moving from development to production. At that time you are asked to optimize indexes, and it is possibly here that the ability to search on a given predicate is dropped. That seemed to be the case for me anyway.