This time I would like to access Google Calendar from the iOS app through the Google Calenear API.
Environment: Xcode 12.0, Swift 5
First, go to Google Cloud Platform and enable the Google Calendar API. Next, get the OAuth client ID for OAuth authentication. Follow the procedure described in "Registering a client ID" in the following article to apply for a client ID.
I hit Google Calendar API with Swift4
The Google API itself is a REST API, but it's hard to call it directly, so I'll use an external library. This time we will use the following libraries.
・ Google authentication AppAuth GTMAppAuth
・ Access to Google Calendar GoogleAPIClientForREST/Calendar
All of the above libraries can be installed at CocoaPods. Write the Podfile as shown below and execute pod install to install it.
platform :ios, '14.0'
target 'GoogleCalendarSample' do
use_frameworks!
pod 'AppAuth'
pod 'GTMAppAuth'
pod 'GoogleAPIClientForREST/Calendar'
end
Now, we will implement the process of performing Google authentication using AppAuth and GTMAppAuth.
First, add the OIDExternalUserAgentSession class to AppDelegate.
AppDelegate.swift
import UIKit
import AppAuth
import GTMAppAuth
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
var currentAuthorizationFlow: OIDExternalUserAgentSession?
---------------- (The following is omitted) ----------------
Then describe the following process on the screen for Google authentication.
import UIKit
import AppAuth
import GTMAppAuth
import GoogleAPIClientForREST
---------------- (Omission) ----------------
private var authorization: GTMAppAuthFetcherAuthorization?
private let clientID = "xxxxxxxxxxxxxxxxxxxx"
private let reverseClientID = "xxxxxxxxxxxxxxxxxxxx"
typealias showAuthorizationDialogCallBack = ((Error?) -> Void)
private func showAuthorizationDialog(callBack: @escaping showAuthorizationDialogCallBack) {
let scopes = ["https://www.googleapis.com/auth/calendar","https://www.googleapis.com/auth/calendar.readonly","https://www.googleapis.com/auth/calendar.events","https://www.googleapis.com/auth/calendar.events.readonly"]
let configuration = GTMAppAuthFetcherAuthorization.configurationForGoogle()
let redirectURL = URL.init(string: reverseClientID + ":/oauthredirect")
let request = OIDAuthorizationRequest.init(configuration: configuration,
clientId: clientID,
scopes: scopes,
redirectURL: redirectURL!,
responseType: OIDResponseTypeCode,
additionalParameters: nil)
let appDelegate: AppDelegate = UIApplication.shared.delegate as! AppDelegate
appDelegate.currentAuthorizationFlow = OIDAuthState.authState(
byPresenting: request,
presenting: self,
callback: { (authState, error) in
if let error = error {
NSLog("\(error)")
} else {
if let authState = authState {
self.authorization = GTMAppAuthFetcherAuthorization.init(authState: authState)
GTMAppAuthFetcherAuthorization.save(self.authorization!, toKeychainForName: "authorization")
}
}
callBack(error)
})
}
The following variables describe the ID obtained when the OAuth client ID was obtained. Enter the OAuth 2.0 client ID in clientID and the reverse client ID in reverseClientID.
private let clientID = "xxxxxxxxxxxxxxxxxxxx"
private let reverseClientID = "xxxxxxxxxxxxxxxxxxxx"
Set the permissions you need this time to the array scopes. This time we are requesting permission to search and change Google Calendar.
let scopes = ["https://www.googleapis.com/auth/calendar","https://www.googleapis.com/auth/calendar.readonly","https://www.googleapis.com/auth/calendar.events","https://www.googleapis.com/auth/calendar.events.readonly"]
When the authState method of the OIDAuthState class is executed, the following Google authentication dialog will be displayed. If the user correctly enters the gmail address and password in the dialog and authentication is complete, the Callback function of the authState method will generate and save the GTMAppAuthFetcherAuthorization class. There is no need to redisplay the authentication dialog while this GTMAppAuthFetcherAuthorization class remains.
Next, I would like to access Google Calendar using GoogleAPIClientForREST. First of all, I will describe the process of getting an existing event from Google Calendar. If you pass the start date and time and end date and time to the get method, it is a program that searches for events between the start date and time and the end date and time from Google Calendar.
import UIKit
import AppAuth
import GTMAppAuth
import GoogleAPIClientForREST
---------------- (Omission) ----------------
private var authorization: GTMAppAuthFetcherAuthorization?
private let clientID = "xxxxxxxxxxxxxxxxxxxx"
private let reverseClientID = "xxxxxxxxxxxxxxxxxxxx"
typealias showAuthorizationDialogCallBack = ((Error?) -> Void)
struct GoogleCalendaraEvent {
var id: String
var name: String
var startDate: Date?
var endDate: Date?
}
private var googleCalendarEventList: [GoogleCalendaraEvent] = []
private func showAuthorizationDialog(callBack: @escaping showAuthorizationDialogCallBack) {
---------------- (Omission) ----------------
}
private func get(startDateTime: Date, endDateTime: Date) {
if GTMAppAuthFetcherAuthorization(fromKeychainForName: "authorization") != nil {
self.authorization = GTMAppAuthFetcherAuthorization(fromKeychainForName: "authorization")!
}
if self.authorization == nil {
showAuthorizationDialog(callBack: {(error) -> Void in
if error == nil {
self.getCalendarEvents(startDateTime: startDateTime, endDateTime: endDateTime)
}
})
} else {
self.getCalendarEvents(startDateTime: startDateTime, endDateTime: endDateTime)
}
}
private func getCalendarEvents(startDateTime: Date, endDateTime: Date) {
let calendarService = GTLRCalendarService()
calendarService.authorizer = self.authorization
calendarService.shouldFetchNextPages = true
let query = GTLRCalendarQuery_EventsList.query(withCalendarId: "primary")
query.timeMin = GTLRDateTime(date: startDateTime)
query.timeMax = GTLRDateTime(date: endDateTime)
calendarService.executeQuery(query, completionHandler: { (ticket, event, error) -> Void in
if let error = error {
NSLog("\(error)")
} else {
if let event = event as? GTLRCalendar_Events, let items = event.items {
self.googleCalendarEventList.removeAll()
for item in items {
let id: String = item.identifier ?? ""
let name: String = item.summary ?? ""
let startDate: Date? = item.start?.dateTime?.date
let endDate: Date? = item.end?.dateTime?.date
self.googleCalendarEventList.append(GoogleCalendaraEvent(id: id, name: name, startDate: startDate, endDate: endDate))
}
}
}
})
}
First, check if Google authentication is complete. Check if the GTMAppAuthFetcherAuthorization class is saved, and if it is not saved, call the showAuthorizationDialog function created earlier to display the Google authentication dialog and get the GTMAppAuthFetcherAuthorization class. If the GTMAppAuthFetcherAuthorization class is saved, use it as it is.
Then use GoogleAPIClientForREST to get the event from the Googl calendar. First, generate the GTLRCalendarService class to access the Goole calendar and set the GTMAppAuthFetcherAuthorization class in the authorizer property.
let calendarService = GTLRCalendarService()
calendarService.authorizer = self.authorization
calendarService.shouldFetchNextPages = true
Next, generate the GTLRCalendarQuery_EventsList class to search for events from Google Calendar, and set the start date and time and end date and time as search conditions.
let query = GTLRCalendarQuery_EventsList.query(withCalendarId: "primary")
query.timeMin = GTLRDateTime(date: startDateTime)
query.timeMax = GTLRDateTime(date: endDateTime)
Then, with this GTLRCalendarQuery_EventsList class as an argument, execute the executeQuery method of the GTLRCalendarService class to get the event from Google Calendar. When the event can be acquired, the GTLRCalendar_Events class is returned by the Callback function of the executeQuery method, so the event information is acquired from here.
if let event = event as? GTLRCalendar_Events, let items = event.items {
self.googleCalendarEventList.removeAll()
for item in items {
let id: String = item.identifier ?? ""
let name: String = item.summary ?? ""
let startDate: Date? = item.start?.dateTime?.date
let endDate: Date? = item.end?.dateTime?.date
self.googleCalendarEventList.append(GoogleCalendaraEvent(id: id, name: name, startDate: startDate, endDate: endDate))
}
}
Especially the identifier (unique ID of the event) is important. This identifier is the key when changing or deleting an event.
Next, I would like to add an event to Google Calendar. It is a program that creates an event in Google Calendar by passing the event name, start date and time, and end date and time to the add method.
import UIKit
import AppAuth
import GTMAppAuth
import GoogleAPIClientForREST
---------------- (Omission) ----------------
private var authorization: GTMAppAuthFetcherAuthorization?
typealias showAuthorizationDialogCallBack = ((Error?) -> Void)
private func showAuthorizationDialog(callBack: @escaping showAuthorizationDialogCallBack) {
---------------- (Omission) ----------------
}
private func add(eventName: String, startDateTime: Date, endDateTime: Date) {
if GTMAppAuthFetcherAuthorization(fromKeychainForName: "authorization") != nil {
self.authorization = GTMAppAuthFetcherAuthorization(fromKeychainForName: "authorization")!
}
if self.authorization == nil {
showAuthorizationDialog(callBack: {(error) -> Void in
if error == nil {
self.addCalendarEvent(eventName: eventName, startDateTime: startDateTime, endDateTime: endDateTime)
}
})
} else {
self.addCalendarEvent(eventName: eventName, startDateTime: startDateTime, endDateTime: endDateTime)
}
}
private func addCalendarEvent(eventName: String, startDateTime: Date, endDateTime: Date) {
let calendarService = GTLRCalendarService()
calendarService.authorizer = self.authorization
calendarService.shouldFetchNextPages = true
let event = GTLRCalendar_Event()
event.summary = eventName
let gtlrDateTimeStart: GTLRDateTime = GTLRDateTime(date: startDateTime)
let startEventDateTime: GTLRCalendar_EventDateTime = GTLRCalendar_EventDateTime()
startEventDateTime.dateTime = gtlrDateTimeStart
event.start = startEventDateTime
let gtlrDateTimeEnd: GTLRDateTime = GTLRDateTime(date: endDateTime)
let endEventDateTime: GTLRCalendar_EventDateTime = GTLRCalendar_EventDateTime()
endEventDateTime.dateTime = gtlrDateTimeEnd
event.end = endEventDateTime
let query = GTLRCalendarQuery_EventsInsert.query(withObject: event, calendarId: "primary")
calendarService.executeQuery(query, completionHandler: { (ticket, event, error) -> Void in
if let error = error {
NSLog("\(error)")
}
})
}
The process up to the generation of the GTLRCalendarService class is the same as in the case of search, so we will explain from the subsequent part. Generate GTLRCalendar_Event class to set the information of the event to be added. Since the event name, start date and time, and end date and time are set this time, they are set in the summary property, start property, and end property of the GTLRCalendar_Event class.
let event = GTLRCalendar_Event()
event.summary = eventName
let gtlrDateTimeStart: GTLRDateTime = GTLRDateTime(date: startDateTime)
let startEventDateTime: GTLRCalendar_EventDateTime = GTLRCalendar_EventDateTime()
startEventDateTime.dateTime = gtlrDateTimeStart
event.start = startEventDateTime
let gtlrDateTimeEnd: GTLRDateTime = GTLRDateTime(date: endDateTime)
let endEventDateTime: GTLRCalendar_EventDateTime = GTLRCalendar_EventDateTime()
endEventDateTime.dateTime = gtlrDateTimeEnd
event.end = endEventDateTime
In addition, the identifier that becomes the unique ID of the event is automatically assigned by Google Calendar in the case of new addition, so it is not necessary to set it here.
Then, generate a GTLRCalendarQuery_EventsInsert class for adding a new event to Google Calendar with the GTLRCalendar_Event class as an argument, and execute the executeQuery method of the GTLRCalendarService class to add a new event to Google Calendar.
Next, let's change the information of the existing event. It is a program that changes the event information of the corresponding identifier in Google Calendar when the event identifier, event name, start date and time, end date and time are passed to the update method.
import UIKit
import AppAuth
import GTMAppAuth
import GoogleAPIClientForREST
---------------- (Omission) ----------------
private var authorization: GTMAppAuthFetcherAuthorization?
typealias showAuthorizationDialogCallBack = ((Error?) -> Void)
private func showAuthorizationDialog(callBack: @escaping showAuthorizationDialogCallBack) {
---------------- (Omission) ----------------
}
private func update(eventId: String, eventName: String, startDateTime: Date, endDateTime: Date) {
if GTMAppAuthFetcherAuthorization(fromKeychainForName: "authorization") != nil {
self.authorization = GTMAppAuthFetcherAuthorization(fromKeychainForName: "authorization")!
}
if self.authorization == nil {
showAuthorizationDialog(callBack: {(error) -> Void in
if error == nil {
self.updateCalendarEvent(eventId: eventId, eventName: eventName, startDateTime: startDateTime, endDateTime: endDateTime)
}
})
} else {
self.updateCalendarEvent(eventId: eventId, eventName: eventName, startDateTime: startDateTime, endDateTime: endDateTime)
}
}
private func updateCalendarEvent(eventId: String, eventName: String, startDateTime: Date, endDateTime: Date) {
let calendarService = GTLRCalendarService()
calendarService.authorizer = self.authorization
calendarService.shouldFetchNextPages = true
let event = GTLRCalendar_Event()
event.identifier = eventId
event.summary = eventName
let gtlrDateTimeStart: GTLRDateTime = GTLRDateTime(date: startDateTime)
let startEventDateTime: GTLRCalendar_EventDateTime = GTLRCalendar_EventDateTime()
startEventDateTime.dateTime = gtlrDateTimeStart
event.start = startEventDateTime
let gtlrDateTimeEnd: GTLRDateTime = GTLRDateTime(date: endDateTime)
let endEventDateTime: GTLRCalendar_EventDateTime = GTLRCalendar_EventDateTime()
endEventDateTime.dateTime = gtlrDateTimeEnd
event.end = endEventDateTime
let query = GTLRCalendarQuery_EventsUpdate.query(withObject: event, calendarId: "primary", eventId: eventId)
calendarService.executeQuery(query, completionHandler: { (ticket, event, error) -> Void in
if let error = error {
NSLog("\(error)")
}
})
}
For update, set the ID of the corresponding event in the identifier property of the GTLRCalendar_Event class. Then set the value you want to change to a property of the GTLRCalendar_Event class. After that, generate GTLRCalendarQuery_EventsUpdate class for updating Google Calendar events with GTLRCalendar_Event class as an argument, and execute the executeQuery method of GTLRCalendarService class with that as an argument.
Finally, delete the event in Google Calendar. It is a program that deletes the corresponding event from Google Calendar when the identifier of the event is passed to the delete method.
import UIKit
import AppAuth
import GTMAppAuth
import GoogleAPIClientForREST
---------------- (Omission) ----------------
private var authorization: GTMAppAuthFetcherAuthorization?
typealias showAuthorizationDialogCallBack = ((Error?) -> Void)
private func showAuthorizationDialog(callBack: @escaping showAuthorizationDialogCallBack) {
---------------- (Omission) ----------------
}
private func delete(eventId: String) {
if GTMAppAuthFetcherAuthorization(fromKeychainForName: "authorization") != nil {
self.authorization = GTMAppAuthFetcherAuthorization(fromKeychainForName: "authorization")!
}
if self.authorization == nil {
showAuthorizationDialog(callBack: {(error) -> Void in
if error == nil {
self.deleteCalendarEvent(eventId: eventId)
}
})
} else {
self.deleteCalendarEvent(eventId: eventId)
}
}
private func deleteCalendarEvent(eventId: String) {
let calendarService = GTLRCalendarService()
calendarService.authorizer = self.authorization
calendarService.shouldFetchNextPages = true
let query = GTLRCalendarQuery_EventsDelete.query(withCalendarId: "primary", eventId: eventId)
calendarService.executeQuery(query, completionHandler: { (ticket, event, error) -> Void in
if let error = error {
NSLog("\(error)")
}
})
}
The deletion can be done by generating the GTLRCalendarQuery_EventsDelete class with the event identifier as an argument and executing the executeQuery method of GTLRCalendarService with that as an argument.
The sample program created this time is available on GitHub. https://github.com/naosekig/GoogleCalendarSample
CocoaDocs.org - GoogleAPIClientForRest I tried hitting Google Calendar API with Qiita: Swift4
Recommended Posts