184

Is there any way to add iCal event to the iPhone Calendar from the custom App?

TheNeil
  • 3,321
  • 2
  • 27
  • 52
Vadim
  • 9,383
  • 7
  • 36
  • 58

11 Answers11

169

Based on Apple Documentation, this has changed a bit as of iOS 6.0.

1) You should request access to the user's calendar via "requestAccessToEntityType:completion:" and execute the event handling inside of a block.

2) You need to commit your event now or pass the "commit" param to your save/remove call

Everything else stays the same...

Add the EventKit framework and #import <EventKit/EventKit.h> to your code.

In my example, I have a NSString *savedEventId instance property.

To add an event:

    EKEventStore *store = [EKEventStore new];
    [store requestAccessToEntityType:EKEntityTypeEvent completion:^(BOOL granted, NSError *error) {
        if (!granted) { return; }
        EKEvent *event = [EKEvent eventWithEventStore:store];
        event.title = @"Event Title";
        event.startDate = [NSDate date]; //today
        event.endDate = [event.startDate dateByAddingTimeInterval:60*60];  //set 1 hour meeting
        event.calendar = [store defaultCalendarForNewEvents];
        NSError *err = nil;
        [store saveEvent:event span:EKSpanThisEvent commit:YES error:&err];
        self.savedEventId = event.eventIdentifier;  //save the event id if you want to access this later
    }];

Remove the event:

    EKEventStore* store = [EKEventStore new];
    [store requestAccessToEntityType:EKEntityTypeEvent completion:^(BOOL granted, NSError *error) {
        if (!granted) { return; }
        EKEvent* eventToRemove = [store eventWithIdentifier:self.savedEventId];
        if (eventToRemove) {
            NSError* error = nil;
            [store removeEvent:eventToRemove span:EKSpanThisEvent commit:YES error:&error];
        }
    }];

This adds events to your default calendar, if you have multiple calendars then you'll have find out which one that is

Swift version

You need to import the EventKit framework

import EventKit

Add event

let store = EKEventStore()
store.requestAccessToEntityType(.Event) {(granted, error) in
    if !granted { return }
    var event = EKEvent(eventStore: store)
    event.title = "Event Title"
    event.startDate = NSDate() //today
    event.endDate = event.startDate.dateByAddingTimeInterval(60*60) //1 hour long meeting
    event.calendar = store.defaultCalendarForNewEvents
    do {
        try store.saveEvent(event, span: .ThisEvent, commit: true)
        self.savedEventId = event.eventIdentifier //save event id to access this particular event later
    } catch {
        // Display error to user
    }
}

Remove event

let store = EKEventStore()
store.requestAccessToEntityType(EKEntityTypeEvent) {(granted, error) in
    if !granted { return }
    let eventToRemove = store.eventWithIdentifier(self.savedEventId)
    if eventToRemove != nil {
        do {
            try store.removeEvent(eventToRemove, span: .ThisEvent, commit: true)
        } catch {
            // Display error to user
        }
    }
}
Cœur
  • 37,241
  • 25
  • 195
  • 267
William T.
  • 12,831
  • 4
  • 56
  • 53
  • 6
    does not work for me, everything goes w/o errors but no event in calendar – Boris Gafurov Oct 02 '13 at 15:30
  • Everything is storing in ekevent object but not storing inside the calendar hlp me –  Jan 28 '14 at 10:02
  • 1
    @William T: Can I present Add Event screen of Calendar app (using URL Scheme) and pass event's info so that when Add Event screen appear, it will have pre filled data. User just need to press add event button. In your example event added without any indication to user. – Ans May 17 '14 at 10:01
  • 1
    if all seems to work yet no calendar appears, check to see if Cloud VS Local calendars is the issue. If you have a mix of Cloud and Local Calendars, Cloud calendars can force the local calendars to become hidden. – zonabi Jun 09 '14 at 17:19
  • @William It is working for me. Here i am facing one problem if i add more than one events to the calendar and tried to remove event from the calendar, It is removing only last event from the calendar. How to get identifier for event when we are removing from the calendar. – Logger Sep 29 '14 at 08:31
  • 2
    @ReddyBasha when you add the event, you need to save off the eventIdentifier and store it for future use. You should use that event id when you go to remove it. – William T. Nov 03 '14 at 00:10
153

You can do this using the Event Kit framework in OS 4.0.

Right click on the FrameWorks group in the Groups and Files Navigator on the left of the window. Select 'Add' then 'Existing FrameWorks' then 'EventKit.Framework'.

Then you should be able to add events with code like this:

#import "EventTestViewController.h"
#import <EventKit/EventKit.h>

@implementation EventTestViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    EKEventStore *eventStore = [[EKEventStore alloc] init];

    EKEvent *event  = [EKEvent eventWithEventStore:eventStore];
    event.title     = @"EVENT TITLE";

    event.startDate = [[NSDate alloc] init];
    event.endDate   = [[NSDate alloc] initWithTimeInterval:600 sinceDate:event.startDate];

    [event setCalendar:[eventStore defaultCalendarForNewEvents]];
    NSError *err;
    [eventStore saveEvent:event span:EKSpanThisEvent error:&err];       
}

@end
Piotr Byzia
  • 3,363
  • 7
  • 42
  • 62
WoodenKitty
  • 6,521
  • 8
  • 53
  • 73
  • 18
    Thanks for posting this. Just a reminder to all who read this: take care to watch for memory leaks. There are a couple in this code sample. Also, best practices would dictate that you check the value of 'err' after saveEvent:span:error and handle things accordingly. – David Carney Jul 06 '10 at 21:37
  • Do you know how to add recurrence event? like an event for every monday? – Jay Vachhani Sep 09 '10 at 07:45
  • 5
    Add recurrence event programmatically: check this out http://developer.apple.com/library/ios/#documentation/EventKit/Reference/EKRecurrenceRuleClassRef/Reference/Reference.html#//apple_ref/doc/c_ref/EKRecurrenceRule. Another option is to use the default framework-supplied view controllers for adding/editing events (like the Calendar At-A-Glance app http://bit.ly/cJq4Bh). For this option, see http://developer.apple.com/library/ios/#documentation/EventKitUI/Reference/EKEventEditViewControllerClassRef/Reference/Reference.html – DenTheMan Dec 06 '10 at 10:12
  • To add frameworks in XCode 4 see this SO question: http://stackoverflow.com/questions/3352664/how-to-add-existing-frameworks-in-xcode-4 – Nate Mar 19 '11 at 01:45
  • 1
    4.0? not gonna fly in 6 see above answer – Boris Gafurov Oct 02 '13 at 15:32
13

Yes there still is no API for this (2.1). But it seemed like at WWDC a lot of people were already interested in the functionality (including myself) and the recommendation was to go to the below site and create a feature request for this. If there is enough of an interest, they might end up moving the ICal.framework to the public SDK.

https://developer.apple.com/bugreporter/

keremk
  • 2,303
  • 14
  • 10
12

Calendar access is being added in iPhone OS 4.0:

Calendar Access
Apps can now create and edit events directly in the Calendar app with Event Kit.
Create recurring events, set up start and end times and assign them to any calendar on the device.

Chris S
  • 64,770
  • 52
  • 221
  • 239
6

Swift 4.0 implementation :

use import in top of page by import EventKit

then

@IBAction func addtoCalendarClicked(sender: AnyObject) {

    let eventStore = EKEventStore()

    eventStore.requestAccess( to: EKEntityType.event, completion:{(granted, error) in

        if (granted) && (error == nil) {
            print("granted \(granted)")
            print("error \(error)")

            let event = EKEvent(eventStore: eventStore)

            event.title = "Event Title"
            event.startDate = Date()
            event.endDate = Date()
            event.notes = "Event Details Here"
            event.calendar = eventStore.defaultCalendarForNewEvents

            var event_id = ""
            do {
                try eventStore.save(event, span: .thisEvent)
                event_id = event.eventIdentifier
            }
            catch let error as NSError {
                print("json error: \(error.localizedDescription)")
            }

            if(event_id != ""){
                print("event added !")
            }
        }
    })
}
Axel Guilmin
  • 11,454
  • 9
  • 54
  • 64
Dashrath
  • 2,141
  • 1
  • 28
  • 33
5

You can add the event using the Event API like Tristan outlined and you can also add a Google Calendar event which shows up in the iOS calendar.

using Google's API Objective-C Client

  - (void)addAnEvent {
  // Make a new event, and show it to the user to edit
  GTLCalendarEvent *newEvent = [GTLCalendarEvent object];
  newEvent.summary = @"Sample Added Event";
  newEvent.descriptionProperty = @"Description of sample added event";

  // We'll set the start time to now, and the end time to an hour from now,
  // with a reminder 10 minutes before
  NSDate *anHourFromNow = [NSDate dateWithTimeIntervalSinceNow:60*60];
  GTLDateTime *startDateTime = [GTLDateTime dateTimeWithDate:[NSDate date]
                                                    timeZone:[NSTimeZone systemTimeZone]];
  GTLDateTime *endDateTime = [GTLDateTime dateTimeWithDate:anHourFromNow
                                                  timeZone:[NSTimeZone systemTimeZone]];

  newEvent.start = [GTLCalendarEventDateTime object];
  newEvent.start.dateTime = startDateTime;

  newEvent.end = [GTLCalendarEventDateTime object];
  newEvent.end.dateTime = endDateTime;

  GTLCalendarEventReminder *reminder = [GTLCalendarEventReminder object];
  reminder.minutes = [NSNumber numberWithInteger:10];
  reminder.method = @"email";

  newEvent.reminders = [GTLCalendarEventReminders object];
  newEvent.reminders.overrides = [NSArray arrayWithObject:reminder];
  newEvent.reminders.useDefault = [NSNumber numberWithBool:NO];

  // Display the event edit dialog
  EditEventWindowController *controller = [[[EditEventWindowController alloc] init] autorelease];
  [controller runModalForWindow:[self window]
                          event:newEvent
              completionHandler:^(NSInteger returnCode, GTLCalendarEvent *event) {
                // Callback
                if (returnCode == NSOKButton) {
                  [self addEvent:event];
                }
              }];
}
Iggy
  • 8,463
  • 3
  • 31
  • 21
4

Update for swift 4 for Dashrath answer

import UIKit
import EventKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        let eventStore = EKEventStore()

        eventStore.requestAccess( to: EKEntityType.event, completion:{(granted, error) in

            if (granted) && (error == nil) {


                let event = EKEvent(eventStore: eventStore)

                event.title = "My Event"
                event.startDate = Date(timeIntervalSinceNow: TimeInterval())
                event.endDate = Date(timeIntervalSinceNow: TimeInterval())
                event.notes = "Yeah!!!"
                event.calendar = eventStore.defaultCalendarForNewEvents

                var event_id = ""
                do{
                    try eventStore.save(event, span: .thisEvent)
                    event_id = event.eventIdentifier
                }
                catch let error as NSError {
                    print("json error: \(error.localizedDescription)")
                }

                if(event_id != ""){
                    print("event added !")
                }
            }
        })
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }


}

also don't forget to add permission for calendar usage image for privary setting

luhuiya
  • 2,129
  • 21
  • 20
3

Working code in Swift-4.2

import UIKit
import EventKit
import EventKitUI

class yourViewController: UIViewController{

    let eventStore = EKEventStore()

    func addEventToCalendar() {

    eventStore.requestAccess( to: EKEntityType.event, completion:{(granted, error) in
        DispatchQueue.main.async {
            if (granted) && (error == nil) {
                let event = EKEvent(eventStore: self.eventStore)
                event.title = self.headerDescription
                event.startDate = self.parse(self.requestDetails.value(forKey: "session_time") as? String ?? "")
                event.endDate = self.parse(self.requestDetails.value(forKey: "session_end_time") as? String ?? "")
                let eventController = EKEventEditViewController()
                eventController.event = event
                eventController.eventStore = self.eventStore
                eventController.editViewDelegate = self
                self.present(eventController, animated: true, completion: nil)

            }
        }


       })
    }

}

Now we will get the event screen and here you can also modify your settings:

enter image description here

Now add delegate method to handle Cancel and add the event button action of event screen:

    extension viewController: EKEventEditViewDelegate {

    func eventEditViewController(_ controller: EKEventEditViewController, didCompleteWith action: EKEventEditViewAction) {
        controller.dismiss(animated: true, completion: nil)

    }
}

Note: Don't forget to add NSCalendarsUsageDescription key into info plist.

Alok
  • 24,880
  • 6
  • 40
  • 67
1

Remember to set the endDate to the created event, it is mandatory.

Otherwise it will fail (almost silently) with this error:

"Error Domain=EKErrorDomain Code=3 "No end date has been set." UserInfo={NSLocalizedDescription=No end date has been set.}"

The complete working code for me is:

EKEventStore *store = [EKEventStore new];
[store requestAccessToEntityType:EKEntityTypeEvent completion:^(BOOL granted, NSError *error) {
    if (!granted) { return; }
    EKEvent *calendarEvent = [EKEvent eventWithEventStore:store];
    calendarEvent.title = [NSString stringWithFormat:@"CEmprendedor: %@", _event.name];
    calendarEvent.startDate = _event.date;
    // 5 hours of duration, we must add the duration of the event to the API
    NSDate *endDate = [_event.date dateByAddingTimeInterval:60*60*5];
    calendarEvent.endDate = endDate;
    calendarEvent.calendar = [store defaultCalendarForNewEvents];
    NSError *err = nil;
    [store saveEvent:calendarEvent span:EKSpanThisEvent commit:YES error:&err];
    self.savedEventId = calendarEvent.eventIdentifier;  //saving the calendar event id to possibly deleted them
}];
halbano
  • 1,135
  • 14
  • 34
  • 1
    And also remember that end date must be equal or bigger than the start date. Otherwise, you will get another error. – moody Oct 26 '17 at 12:49
0

Simple.... use tapku library.... you can google that word and use it... its open source... enjoy..... no need of bugging with those codes....

Rajesh_Bangalore
  • 613
  • 5
  • 21
  • 3
    https://developer.apple.com/library/ios/#documentation/DataManagement/Conceptual/EventKitProgGuide/Introduction/Introduction.html#//apple_ref/doc/uid/TP40009765 – Rajesh_Bangalore Aug 28 '12 at 06:27
  • Can Tapku Library calendar synchronise with calender app events – coder1010 Jan 30 '13 at 05:18
  • All i know is that Tapku library is a calendar component control which has an option called Data source. So its upto ur logic to write the where that source you are fetching from... Happy Coding :) – Rajesh_Bangalore Feb 05 '13 at 05:53
0

The Google idea is a nice one, but has problems.

I can successfully open a Google calendar event screen - but only on the main desktop version, and it doesn't display properly on iPhone Safari. The Google mobile calendar, which does display properly on Safari, doesn't seem to work with the API to add events.

For the moment, I can't see a good way out of this one.

xgretsch
  • 1,294
  • 13
  • 15