Advertise

Thursday, March 16, 2017

PART 1: iOS Create custom calendar and manage Events with EventKit in Swift



Introduction:


Reminder, Alarms and Event manager, these are very well known and useful tools for mobile generation. You don't have to remember events or your friend's birthday etc. As a developer, idea may come up to your mind to use and access those events in your application. Well, fortunately apple has given permission to access system calendar to developer via EventKit. EventKit is not so well known framework but it is a middleware between system event database and your application. Your application can access all events and calendars via this framework only.

With help of EventKit framework you can create, update or delete calendar, events and reminders. Before access the system Calendar database, keep in mind you must grant access to Calendar or reminder app. Moreover you need to declare privacy of calendar usage in your project's Info.plist file. User will decide to give calendar access to your app.

In this post, we are not going to do each and every steps for integrating the calendar into app. Rather than that I am going to give you feature code for grant access to use calendar, Creating calendar etc. We can see how to manage Events in next post.

I assume you have knowledge about how to create project and basics of swift:

Ask user to grant Access Calendar


Below code shows you how ask request access to user and know the current authorisation status:

import UIKit
import EventKit

class AskPermissionController: UIViewController {
    let eventStore = EKEventStore()
    override func viewDidLoad() {
        super.viewDidLoad()
    }
    override func viewWillAppear(_ animated: Bool) {
        checkCalendarAuthorizationStatus()
    }
    func checkCalendarAuthorizationStatus() {
        let status = EKEventStore.authorizationStatus(for: EKEntityType.event)
        switch (status) {
        case EKAuthorizationStatus.notDetermined:
            // This happens on first-run
            requestAccessToCalendar()
        case EKAuthorizationStatus.authorized:
            // Yo!! You got a access to use Calendar now go on and create/load all calendar list.
            //loadCalendars()
            //refreshTableView()
            break
        case EKAuthorizationStatus.restricted, EKAuthorizationStatus.denied:
            // We need to create another view which helps user to give us permission
            break
        }
    }
    func requestAccessToCalendar() {
        eventStore.requestAccess(to: EKEntityType.event, completion: {
            (accessGranted: Bool, error: Error?) in
            if accessGranted == true {
                DispatchQueue.main.async(execute: {
                    // Yo!! You got a access to use Calendar now go on and create/load all calendar list.
                    //loadCalendars()
                    //refreshTableView()
                })
            } else {
                DispatchQueue.main.async(execute: {
                    // We need to create another view which helps user to give us permission
                })
            }
        })
    }
}

Add below line to Info.plist:





IMPORTANT: If you forget to declare in plist file, your app will be crashed so don't forget to add above line. It is necessary to give user in knowledge that your app will use their personal calendar data. 

Load All Calendars names into TableView


I assume you have knowledge about TableView in Swift, if not go to this link : Table View in Swift

1. Import EventKit on the top of your class and declare calendar variable as below

var calendars: [EKCalendar]?



2. Create method for load all calendars into given calendars array and call this method to viewDidLoad method:

 func loadCalendars() {
        self.calendars = eventStore.calendars(for: EKEntityType.event)
        //If you want to sort Calendars by name, use below line
//        self.calendars = EKEventStore().calendars(for: EKEntityType.event).sorted() { (cal1, cal2) -> Bool in
//            return cal1.title < cal2.title
//        }
    }


3. Update cellForRowAt method of TableView as below:


func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        if let calendars = self.calendars {
            return calendars.count
        }
        return 0
    }
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "Cell")!
        if let calendars = self.calendars {
            let calendarName = calendars[(indexPath as NSIndexPath).row].title
            print("Calendar Name : \(calendarName)")
            cell.textLabel?.text = calendarName
        } else {
            print("Unknown Calendar Name")
            cell.textLabel?.text = "Unknown Calendar Name"
        }
        return cell
    } 

DONE ! Above code will display list of all Calendar names. Next Step is to create your own Calendar through your application.

Create own calendar

Simple few line of code will create a new calendar as below: If you want to set user defined calendar name then,
1. Create another class named AddCalendarController.swift. 
2. Add UITextField and declare it as a newCalendarField into swift file
3. on Save button, paste below code.

@IBAction func saveNewCalendarAction(_ sender: UIBarButtonItem) {
        // Create an Event Store instance
        let eventStore = EKEventStore();
        
        // Use Event Store to create a new calendar instance
        // Configure its title
        let newCalendar = EKCalendar(for: .event, eventStore: eventStore)
        
        // Probably want to prevent someone from saving a calendar
        // if they don't type in a name...
        newCalendar.title = newCalendarField.text ?? "Some Calendar Name"
        
        // Access list of available sources from the Event Store
        let sourcesInEventStore = eventStore.sources
        
        // Filter the available sources and select the "Local" source to assign to the new calendar's
        // source property
        newCalendar.source = sourcesInEventStore.filter{
            (source: EKSource) -> Bool in
            source.sourceType.rawValue == EKSourceType.local.rawValue
            }.first!
        
        // Save the calendar using the Event Store instance
        do {
            try eventStore.saveCalendar(newCalendar, commit: true)
            UserDefaults.standard.set(newCalendar.calendarIdentifier, forKey: "EventTrackerPrimaryCalendar")
            self.navigationController?.popViewController(animated: true)
            //self.dismiss(animated: true, completion: nil)
        } catch {
            let alert = UIAlertController(title: "Calendar could not save", message: (error as NSError).localizedDescription, preferredStyle: .alert)
            let OKAction = UIAlertAction(title: "OK", style: .default, handler: nil)
            alert.addAction(OKAction)
            self.navigationController?.popViewController(animated: true)
            //self.present(alert, animated: true, completion: nil)
        }
    }

NOTE: Do not forget to import EventKit in the swift file

Create, manage, update, delete events using EventKit. Go To PART 2: Manage Events using EventKit Framework in Swift


If you want to download full source code, click below link. Demo code has a feature of:
  • Ask permission and grant access to use Calendar
  • Create Calendar and get a list of all Calendars
  • Create,Update,Delete,Get Events


Download Full Source Code




2 comments: