How to use the Google Calendar API on iOS

As you all know, a few weeks ago Apple published Xcode 7.3 with iOS 9.3. I ended up dealing with a lot of problems that kept cropping up while I tried to use some Google libraries that used to work fine. In this post, I'll go over these library issues. While we're at it, we'll also build a cool new app for adding Google Calendar events!

Issues with Google Libraries

For starters, when I tried to build one of the projects with Xcode 7.3 it failed to build, pointing at this Google library:

Old: gdata-objectivec-client: https://github.com/google/gdata-objectivec-client

New: google-api-objectivec-client https://github.com/google/google-api-objectivec-client

At first I thought that it had a newer version than what we had been using in our project, and that after a simple update everything would be ok. Wrong! After some Googling I realized that the library is not supported anymore and there is a newer one that is officially supported by Google.

All I needed to do was to change deprecated library with the new one, right? Well, it's not as simple as I thought it would be.

Adding GoogleAPIClient as a pod

I admit this first part was simple. I removed the old library from the project manually then I tried adding the new library as a pod using Cocoapods.

Make sure to add right pod name into the Podfile

If you search for a pod name like this in search bar of the Cocoapods website, you will see two results: Google-API-Client and GoogleAPIClient. Be careful, the correct one is GoogleAPIClient.

Right pod name

So the right line for your podfile should be;
pod 'GoogleAPIClient'

Some time later, I figured out that if I want to find the correct pod name, all I have to do is to look into the .podspec file for any pod library. In this case, GoogleAPIClient.podspec tells us the right pod name with this line:

s.name = 'GoogleAPIClient'

GoogleAPIClient library includes number of different APIs inside it, and it keeps them as subspecs that you can check out in GoogleApiClient.podspec. In our project, only the Google Calendar API is being used. Therefore, my podfile just includes:

pod 'GoogleAPIClient/Calendar'

This way, only the files required by the Calendar API will be added into the project after installing the pod.

Another important piece information when you use the Calendar API is that you will need the GTM OAuth 2 library for authenticating users into their Google accounts. This library is does not come with pod as a dependency. So I also needed to add it into my podfile as a separate pod:

pod 'GTMOAuth2'

So, my final podfile looks like this:

pod 'GoogleAPIClient'
pod 'GTMOAuth2'

We're not done: Cleaning up GData remnants

After installing pod libraries in my podfile shown above, I encountered a weird problem. I imported GTMOAuth2ViewControllerTouch.h which is included in the GTMOAuth2.

Import statement

Although XCode did not complain about this import, whenever I tried to use any method of GTMOAuth2ViewControllerTouch class I got a use of undeclared identifier error like this:

Use of undeclared identifier

This is caused by these two flags, remnants of the old GData library which I removed before in project settings.

"-DGDATA_REQUIRE_SERVICE_INCLUDES=1"
"-DGDATA_INCLUDE_CALENDAR_SERVICE=1"

They were under OTHER_CFLAGS in .../Project-Name.xcodeproj/project.pbxproj.

After solving these issues, I was finally able to focus on my main task: implementing the ability to add events to Google Calendar for users who have a Google account.

In order to explain event creation in Google Calendar using Google's API, I will use a sample application that I wrote just for you:

Configuring the Google Dev Console

Before using the Google Calendar API, we need to make some configurations on Google's developer console. Most importantly, applications that use Google Calendar API need a client ID. Here's a step-by-step guide on how to get one for a new project.

First open the Developer Console. You will need to create a new project using the panel at the top right of the page (if you don't already have one).

Create or select your project
Google Right top panel

If you create a new project, choose a new name for it. Mine is Google Calendar Sample App.

Choose a project name
Google Select a name for the project

Choose a product name Google product name

Select "OAuth client ID" Google credential selection

Enter a bundle ID
Google bundle id

Finally, you will see a prompt with your client ID.

Get Client ID
Google client id

Make sure to enable Google Calendar API from the console.

Google enable Calendar API 1

Google enable Calendar API 2

Eventbrite configuration

I used Eventbrite's API to show some random events in my sample application. To use this API, you will need a OAuth token which is sent within requests to the API as a parameter for authentication.

Here you can access the app management page in developer portal of Eventbrite. Your personal OAuth token is what you need to make our sample app work.

Eventbrite OAuth token

Building our Sample App

After you get your Google API client ID and Eventbrite OAuth token, just assign them to kGoogleAPIClientID and kEventbriteAuthToken in the code.

Two classes I used from the API are GTLServiceCalendar and GTLCalendarEvent, I needed to define two properties for authentication and saving events.

@property (nonatomic, strong) GTLServiceCalendar *calendarService;
@property (nonatomic, strong) GTLCalendarEvent *calendarEvent;

We can check if a user is authenticated with his Google account by just checking the bool value _calendarService.authorizer.canAuthorize.

_calendarService.authorizer = [GTMOAuth2ViewControllerTouch  
                              authForGoogleFromKeychainForName:kGoogleAPIKeychainItemName
                              clientID:kGoogleAPIClientID
                              clientSecret:nil];

If the user is not authenticated yet, Google's authentication view will be shown. For this we need to use the GTMOAuth2ViewControllerTouch class, which is implemented with this method:

- (void)launchGoogleAuthenticationView {
    _didCancelGoogleAuthentication = NO;

    GTMOAuth2ViewControllerTouch *authController;

    // If modifying these scopes, delete your previously saved credentials by
    // resetting the iOS simulator or uninstall the app.
    NSArray *scopes = [NSArray arrayWithObjects:kGTLAuthScopeCalendar, nil];

    authController = [[GTMOAuth2ViewControllerTouch alloc]
                      initWithScope:[scopes componentsJoinedByString:@" "]
                      clientID:kGoogleAPIClientID
                      clientSecret:nil
                      keychainItemName:kGoogleAPIKeychainItemName
                      delegate:self
                      finishedSelector:@selector(googleAuthenticationViewController:finishedWithAuth:error:)];

    UIButton *closeButton = [UIButton buttonWithType:UIButtonTypeCustom];

    [closeButton setTitle:@"Cancel" forState:UIControlStateNormal];

    [closeButton addTarget:self
                    action:@selector(didTapCloseButton:)
          forControlEvents:UIControlEventTouchUpInside];

    UIBarButtonItem *closeButtonItem = [[UIBarButtonItem alloc]
                                         initWithCustomView:closeButton];

    [authController.navigationItem setLeftBarButtonItem:closeButtonItem];

    UINavigationController *navController = [[UINavigationController alloc]
                                             initWithRootViewController:authController];

    [self presentViewController:navController
                       animated:YES
                     completion:nil];
}

And finally, here is the method I used to add an event to Google Calendar.

- (void)addEventToGoogleCalendar {
    GCAEvent *selectedEvent = _events[_currentSelectedIndexPath.row];

    if (selectedEvent.isAdded) {
        return;
    }

    _calendarEvent = [[GTLCalendarEvent alloc] init];

    [_calendarEvent setSummary:selectedEvent.name];
    [_calendarEvent setDescriptionProperty:selectedEvent.content];

    NSDate *startDate = selectedEvent.startDate;
    NSDate *endDate = selectedEvent.endDate;

    if (endDate == nil) {
        endDate = [startDate dateByAddingTimeInterval:(60 * 60)];
    }

    GTLDateTime *startTime = [GTLDateTime dateTimeWithDate:startDate
                                                  timeZone:[NSTimeZone systemTimeZone]];

    [_calendarEvent setStart:[GTLCalendarEventDateTime object]];
    [_calendarEvent.start setDateTime:startTime];

    GTLDateTime *endTime = [GTLDateTime dateTimeWithDate:endDate
                                                timeZone:[NSTimeZone systemTimeZone]];

    [_calendarEvent setEnd:[GTLCalendarEventDateTime object]];
    [_calendarEvent.end setDateTime:endTime];


    GTLQueryCalendar *insertQuery = [GTLQueryCalendar queryForEventsInsertWithObject:_calendarEvent
                                                                          calendarId:kGoogleAPICalendarID];
    [self showAlertWithTitle:nil
                  andMessage:NSLocalizedString(@"Adding Event…", nil)];

    [_calendarService executeQuery:insertQuery
                 completionHandler:^(GTLServiceTicket *ticket, id object, NSError *error) {
                     if (error == nil) {
                         [self showAlertWithTitle:nil
                                       andMessage:NSLocalizedString(@"Event Added!", nil)];

                         selectedEvent.added = YES;
                         [self.tableView reloadRowsAtIndexPaths:@[_currentSelectedIndexPath]
                                               withRowAnimation:YES];
                     } else {
                         [self showAlertWithTitle:NSLocalizedString(@"Event Entry Failed", nil)
                                       andMessage:NSLocalizedString(@"Could not add event, please try again.", nil)];
                     }
                 }];
}
Conclusion

Well that's about it. I hope this helps you figure out the basics on implementing the Google Calendar API and overcome the few challenges associated with it. Using Eventbrite as a data source for sample events should also be good practice. I hope this helps! Feel free to drop me a line about questions and comments.

Here's my Sample App on Github: https://github.com/eraydiler/GoogleCalendarApi