In my last tutorial we worked with the YouTube API, and through the demo application we managed to make requests to that specific Google API. Actually, we created an API key prior to any request, as that key was vital for every request that was about to return data back to our application. This time, we’ll continue working with the Google APIs, and my goal is to show you how to make authorized requests after a user has signed in with the Google in the application.
For this purpose we are going to use a special SDK, named Google Sign-In SDK. This one provides all the necessary classes and functionalities we need in order to:
- Add the default Google Sign In button in our app.
- Go through the whole user authentication process using the OAuth 2.0 protocol and get the necessary tokens.
Before the Sign-In SDK becomes available, every developer who wanted to allow user authentication in iOS applications and subsequently to perform authorized requests to specific APIs had to manually implement the OAuth 2.0 protocol flow following the rules defined by Google. Trust me, that was a great hassle, as there were several steps needed to be implemented under certain conditions until the desired access and refresh tokens to be fetched. However, all this is just history now. Things have dramatically changed, as the Sign-In button implements and performs the whole OAuth process behind the scenes. After a successful sign in, every iOS app can use the access token (and refresh token) to make authorized requests, and most importantly developers can focus on the application logic only. If you want to read more about the OAuth 2.0 protocol, Google provides a nice documentation page for this reason.
In order for users to sign in with their Google account into an app, it’s required to provide them with an interface to do so. The Sign-In SDK contains a special view controller for this purpose, so there’s no need to call any external browser or implement in-app web views. We’ll see the details later on. Right before you ask from users to sign in, it’s important to determine the scopes of the API you want to access. A scope actually describes the part of the API (or APIs) that you want your app to have access to. During the sign in process, Google makes clear to users what they’re about to authorize the app for in a special web page that appears after the credentials have been entered successfully. If you need user authorization for many scopes, Google suggests to do so incrementally, meaning to ask authorization for scopes right before the respective features to be used (see more details here).
So, as you understand the first important feature we’ll see here is how to integrate the Sign-In button and how to allow users to sign in. However, doing just that won’t let us make authorized requests, therefore we’ll use the Google+ API as our target API for that purpose. To be more precise, our goal is not to learn how to deal with the Google+ API. This API is really important and quite big so we cover it here. We’ll just use a part of it to make an authorized request using the access token that the Sign-In will make available to the app once a user has signed in. Specifically, we’ll use the People: list method of the API, which returns a list of people existing in the Google+ circles of a user. Among all the available APIs, I personally found this one quite interesting to use in the demo application of this tutorial.
In case you haven’t read the previous tutorial about the YouTube API, I would recommend to do so (or at least the introduction), as everything in this one will come smoother and easier. That doesn’t mean of course that you can’t proceed without it.
Similarly to the previous one, in this tutorial I tried to gather information from various sources in one place too. Right next I give you some useful links that it would be nice to visit.
Demo App Overview
The app that we’ll implement in this post so as to demonstrate all the desired features is parted by two view controllers. In the first one we are going to integrate the Sign-In button, and the app won’t be able to present the second one without a successful sign in from the user. All the sign in and authentication (using the OAuth protocol) process will be handled by the Sign-In SDK. A special view controller containing a web view will be presented to let users enter the sign-in credentials, and then to accept all the given scopes. Some basic user profile data (such as the name and the email) is asked to be accepted by default. In addition to them, we will ask for authorization regarding two more scopes, so we can later get the people list from the Google+ circles. All the details will be given later.
In the second view controller there is a tableview and a toolbar with two bar button items. These items will be used to sign out and to disconnect the Google account from the app respectively. There is a difference between these two actions that I will explain when we’ll get to that part. Regarding the tableview, we are going to have two sections. In the first section we’ll have just two rows, where we’ll display just the user’s real name and the email address. In the second section we’ll list all the people of the Google+ circles that we’ll fetch by making the request to the Google+ API. The only piece of information that we’ll display in this case is the image and the name of each person.
Right next you can see samples of the two view controllers:
Similarly to the most of my tutorials, you can get a starter project to work with. When you open it, you’ll see that some basic implementation already exists. Among all the code, you will find a method in the ContentViewController named performGetRequest(…). We had implemented and discussed about that method in the previous tutorial (in the YouTube API tutorial), so look there for details about it.
Notice: In case you download the final project to test the app, perform the following actions before the first run:
- Create a client ID and enable the OAuth 2.0 in the Developers Console.
- In the GoogleServices-Info.plist file set the proper CLIENT_ID and REVERSED_CLIENT_ID values.
- In the ViewController class set the proper client ID value to the clientID property of the GIDSignIn singleton.
- In the Project > Target > Info > URL Types section, set the proper Bundle ID and Reversed Client ID values to the URL Schemes.
If those steps rise questions, the next two parts will give all the answers you need.
Enabling the OAuth 2.0 Authentication
In my previous tutorial I started the actual post content by describing how to create a new project record in the Google Developers Console. In the same way we are going to start off here too (with a bit less details). That’s because we have to enable the OAuth 2.0 authentication mechanism so we can use the Google Sign-In button and perform authorized requests.
So, follow the above link and get connected to the Developers Console. The first step is to click to the Create Project blue button, and add a new project that will be connected to our iOS project. For the purposes of this tutorial I named the new project GSignIn, however that’s something you can change if you want.
By creating it you’ll be navigated to another page where you can perform various actions on it. Such an action is to enable the Google+ API, and you’ll manage it by going to the APIs & auth > APIs menu option. Under the Social APIs section you’ll find the Google+ API link, which you have to click. In the next page just click to the Enable API blue button.
Next, go to the APIs & auth > Consent screen option. Here you can specify the information that will be displayed to the default Google’s consent screen that will be shown when we’ll use the Sign-In button to sign in. From all the given fields, the only one that has to be necessarily filled in is the Product Name. So, just type the project’s name and you’re good to go.
Lastly, let’s enable the OAuth 2.0 authentication, so we can access private data by making authorized requests. This time, follow the APIs & auth > Credentials link, and then click to the Create new Client ID button. You are provided with various options in the modal window, but we only care about the Installed application option. In the details that appear by selecting it, choose (obviously) the iOS application type. As a last step, type the Bundle ID of the app in the respective field. What I used is the com.appcoda.GSignIn value, but you should change it according to your bundle ID.
You’ll notice that some details regarding the new client ID will appear in the credentials page when you click to the Create Client ID button. All this data shown here is going to be used later during the sign-in process.
For the time being we’ve done our job in the Developers Console, however don’t close the browser/tab yet. We’ll come back shortly to copy the client ID value.
Preparing the Project
In this part we’ll download the Sign-In SDK and we’ll perform all the required configuration in our iOS project so we can successfully sign in later in the app. Note at this point that there are two ways to install and configure the Sign-In SDK; the first one is to use CocoaPods and the second is to go in a more manual way. Here I chose to present the last one, but you can find guidance regarding the first option in the respective documentation.
First of all, the initial step is to get the Sign-In SDK for iOS (you should always make sure that you download the latest version. Once you download it, extract the compressed file’s contents and add both the GoogleSignIn.framework and the GoogleSignIn.bundle files to the project. You can follow two ways to do that: Either to drag and drop each one to the Project Navigator, or to use the File > Add Files to “GSignIn”… option in Xcode (which I consider to be a safer method; use it if the drag-and-drop method won’t work). At the end, you should see both of them in your Project Navigator:
The Sign-In SDK requires some specific frameworks to be added and linked to the project, therefore this is going to be our next step. In Xcode, go to the Project > Target > General tab > Linked Frameworks and Libraries section, and use the plus button to add the following three frameworks:
- SystemConfiguration.framework
- StoreKit.framework
- AddressBook.framework
Next, we must create a property list (plist) file that will contain two values only: The client ID as it was generated in the Developers Console, and a semi-reversed form of the client ID value. Before I describe the details, go to the File > New > File… menu in Xcode, and select an iOS > Resource > Property List file type to create a new .plist file. It’s really important to name that file GoogleService-Info.plist, as this is the name is used by the SDK to look it up. Once that file is ready and added to the Project Navigator, open it and add two entries. Here are the details:
- In the first one, set the CLIENT_ID key, and in the value field copy-and-paste the generated client ID from the Developers Console.
- In the second, set the REVERSED_CLIENT_ID key, and form the value as follows: Begin by writing (or pasting) the com.googleusercontent.apps. string and right after paste just the numerical value of the client ID (i.e. the string right before “.apps.googleusercontent.com”).
In other words, in the CLIENT_ID entry add the com.googleusercontent.apps string right after the numerical value (as it originally is), and in the REVERSED_CLIENT_ID entry use that string as a prefix and don’t append it to the end.
An alternative way to producing the above file, is to let Google prepare it for you. Visit this page, select the proper app name and bundle ID values, and follow the guide. At the end, the GoogleService-Info.plist file will be ready to download, so all you have to do is to add it to the project.
Continuing to the project configuration now, go to the Project > Target > Info > URL Types section in Xcode. Here we must add two URL schemes that the Sign-In SDK needs to be properly set up so as to properly work. Use the plus button, and in the URL Schemes field just type the app bundle ID value (e.g. com.appcoda.GSignIn). Next, add one more scheme, and add the reversed client ID value to the respective field.
When you get finished with the URL schemes, go to the Project > Target > Build Settings tab. There, scroll down and locate the Linking section, and more specifically the Other Linker Flags entry. Double-click to the (empty) value, and type the -ObjC string. This will make possible to use the Objective-C libraries of the Sign-In SDK in Swift.
Lastly, we are going to need a bridging header file to import the SDK libraries (as I just said it is written in Objective-C). In the starter project you’ve downloaded, you’ll find a bridging header file already being there, named GSignIn-Bridging-Header.h. Click it to open it, and add the following single line:
#import
And with that, all the initial and required configuration is over. I admit that we’ve had more than a few steps to make, but that way we ensure that everything is about to work properly. Let’s write some code now.
Getting Ready to Sign In
According to what I’ve already explained in the introduction, when using the Sign-In button a built-in (to the SDK) view controller is presented with a web view in it, providing us with all the necessary fields to sign in.
Now that all the previous several steps are over, it’s really easy to display the Google Sign-In button and go through the sign in process. All we have to do is to adopt a couple of new protocols, to properly configure a view and set the scopes of the API that we want to have access to. Besides that, working with the Sign-In SDK it couldn’t be easier, as we are not going to create special objects or instances of classes belonging to SDK; we’ll be using just a singleton class named GIDSignIn. But, let’s see everything in the proper order:
Initially, open the ViewController.swift file as our very first step is to adopt the following two protocols:
class ViewController: UIViewController, GIDSignInDelegate, GIDSignInUIDelegate
Of course, let’s not forget that we should make the ViewController class the delegate of the above two, so inside the viewDidLoad function add the next two simple lines:
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
GIDSignIn.sharedInstance().delegate = self
GIDSignIn.sharedInstance().uiDelegate = self
}
We are going to add one more command along with the above two. In this one, we’ll be setting the client ID value explicitly and directly to the GIDSignIn singleton, so open the GoogleService-Info.plist file, copy the value of the CLIENT_ID entry, and paste it right next:
override func viewDidLoad() {
...
GIDSignIn.sharedInstance().clientID = "YOUR_CLIENT_ID"
}
As we’re currently working in the viewDidLoad function and doing some initial setup, now it’s also the best time to specify the required scopes so we can access the API services we want. I’ve already said that a scope defines the exact services of each API that will become available to an application, and every API has a number of scopes that provide access to every aspect of it. In our case we want two things for us to be available: The signed in user’s personal info (name, email), and the list of people existing in all the Google+ circles. The first part is easily accessible, as there’s no need to specify any scope at all for that; the user’s real name and email address become known by default to the GIDSignIn class when signing in. However, regarding the Google+ API the scopes must be explicitly set, and for getting the list of the people in circles we need the next two scopes:
- https://www.googleapis.com/auth/plus.login
- https://www.googleapis.com/auth/plus.me
Note: Regardless of the signed in user’s real name and email that is by default available through the GIDSignIn class (you’ll see that in a while), you can get the full user’s Google+ profile and gain access to more information as well. In that case, there are two additional scopes that you should use: https://www.googleapis.com/auth/userinfo.email and https://www.googleapis.com/auth/userinfo.profile. However, as we are not going to dive into Google+ API’s details, I only recommend to take a look in the respective official documentation.
Specifying the desired scopes in code-level terms is easy, as all it takes is to append the scope string values to an array named scopes. Here it is:
override func viewDidLoad() {
...
GIDSignIn.sharedInstance().scopes.append("https://www.googleapis.com/auth/plus.login")
GIDSignIn.sharedInstance().scopes.append("https://www.googleapis.com/auth/plus.me")
}
Finally, let’s focus to the Sign-In button. In the Main.storyboard file and more specifically in the View Controller scene, there’s a view object (a UIView, not a UIButton) in the middle of the scene. Select it, and then set the GIDSignInButton class in the Identity Inspector as shown next:
Now, you can return in the ViewController.swift and change the class of the signInButton IBOutlet property from UIView to GIDSignInButton:
@IBOutlet weak var signInButton: GIDSignInButton!
By performing the last actions, we managed to turn a simple UIView object to the desired Sign-In button, and in the next step we’re about to use it for first time.
Sign In
Previously we adopted two protocols to the ViewController class regarding the Sign-In button, and now it’s time to implement a couple of delegate methods. Here they are:
func signIn(signIn: GIDSignIn!, didSignInForUser user: GIDGoogleUser!, withError error: NSError!) {
}
func signIn(signIn: GIDSignIn!, didDisconnectWithUser user: GIDGoogleUser!, withError error: NSError!) {
}
It’s easy to understand what each one is for. The first one is called once a sign in process has finished, no matter if it’s successful or not. The second is called when the uses the disconnect button, but we’ll discuss in details about it in the last part, not now.
Focusing in the first delegate method, it’s simple to think what we want from it: To give us access to the protected part of the app after a successful sign in. That means that all we have to do is to check if any error has occurred, and if not, to perform the segue that will take us to the ContentViewController scene. Otherwise, we’ll just display the error message.
func signIn(signIn: GIDSignIn!, didSignInForUser user: GIDGoogleUser!, withError error: NSError!) {
if let err = error {
println(error)
}
else {
performSegueWithIdentifier("idSegueContent", sender: self)
}
}
Things so far are pretty clear, as all we have to do is to tap on the Sign-In button, follow the process there, and then the above method will handle the rest. The most important fact here is that the whole authentication (OAuth) process will take place behind the scenes, and after a successful outcome an access token (managed by the GIDSignIn class) will be stored to the app for future usage. However, maybe you’re wondering what is going to happen with subsequent sign in processes? Do we really have to go through the sign in process each time we use the app? Or there’s another simpler way that will automatically sign us in until we explicitly tell the app we want to sign out?
Thankfully, there is such a way, and is called silent sign in. In that case, the user doesn’t have to take any actions at all. Everything happens in the background, where the GIDSignIn class tries to automatically sign in the user, and if it manages it calls the above delegate method. If the automatic sign in fails, the delegate method is called, but this time with an error. During the silent sign in, if everything runs without problems, the access and refresh tokens of the OAuth will be refreshed automatically as well.
Having said all the above, let’s head back to the viewDidLoad and let’s enable the silent sign in as shown next:
override func viewDidLoad() {
...
GIDSignIn.sharedInstance().signInSilently()
}
Now, let’s run the app for first time, and let’s go together through all steps until you get signed in. By launching it for first time (Simulator or device, it doesn’t really matter), you’ll see the following screen with an error message at the same time in the console. That’s because the silent sign in failed, so we can just ignore it.
Tap (or click) on the Sign-In button, and wait until the dedicated view controller is presented. Then, enter your credentials to sign in:
In the next step, you’re given with some descriptions regarding all the Google API aspects that our app asks permission for. Actually, what you see here is the result of the scopes that we set earlier, and of course you’ll see different messages for different scopes. The only exceptions are the last two messages, which appear by default (more precisely, the email address scope can be disabled as well).
You’ll notice that next to some scope descriptions there’s a pencil icon. By tapping on any of them, you can perform further customization or select other sets of options regarding the respective scope. For example, in the second scope above I chose to be the only one knowing that I’ve signed in to this demo app with Google:
Once you go through all the given options, use the Accept button at the bottom side to complete the sign in process. By tapping on it, the OAuth mechanism starts to work, and if nothing bad happens you’ll be taken back to the app while an access token has been fetched in the background. Actually, you won’t just be taken back to the app, but you’ll be navigated to the ContentViewController view controller. For the time being you won’t see any content, but that’s something we’re about to fix starting from the next part.
Displaying Personal Info
If you followed each step as described in the previous parts properly, then you’ve already managed to sign in to the app using your Google account, so the first big goal of this app has been achieved. Now, in both this and the next part we’ll focus on getting and displaying data. In this part, this data will be taken directly from the GIDSignIn class. In the next part, we’ll make an authorized request to the Google+ API and we’ll fetch the data on the fly.
For our purposes here we’ll make use of two classes that the Sign-In SDK contains and that we haven’t seen so far. These are the GIDGoogleUser and the GIDProfileData. Both of them are accessible through the GIDSignIn singleton as properties. More precisely, there is a property named currentUser that is an instance of the GIDGoogleUser class, and this one in turn contains another property named profile which is an instance of the GIDProfileData class.
Note: You can get detailed information about the above classes, as well as all the other classes and protocols that the Sign-In DK contains in this page. It’s a really informative documentation, so don’t miss it.
Now, let’s focus a bit on our demo application, and more specifically let’s deal with the ContentViewController class. I’ve said already in the application overview part that the tableview in this view controller will have two sections: In the first one we’ll display two rows with the name and email address of the signed in user, while in the second section we’ll list all the people existing in the Google+ circles of the user. So, let’s dive in the details of the first case, and let’s see how we can get the desired values using the classes I mentioned about previously.
Right now, you can find the following implementation in the ContentViewController.swift file:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell: UITableViewCell!
if indexPath.section == 0 {
cell = tableView.dequeueReusableCellWithIdentifier("idCellPersonalInfo", forIndexPath: indexPath) as! UITableViewCell
}
else {
cell = tableView.dequeueReusableCellWithIdentifier("idCellPeople", forIndexPath: indexPath) as! UITableViewCell
}
return cell
}
As you can see, in the first case we dequeue the idCellPersonalInfo prototype cell, but as no values are assigned to the text and detail text labels, we’ll do so now. In the following code segment we add the missing implementation in the if body, where we assign the name and email values to the text labels depending on the row index:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell: UITableViewCell!
if indexPath.section == 0 {
cell = tableView.dequeueReusableCellWithIdentifier("idCellPersonalInfo", forIndexPath: indexPath) as! UITableViewCell
if indexPath.row == 0 {
cell.textLabel?.text = GIDSignIn.sharedInstance().currentUser.profile.name
cell.detailTextLabel?.text = "Name"
}
else {
cell.textLabel?.text = GIDSignIn.sharedInstance().currentUser.profile.email
cell.detailTextLabel?.text = "Email"
}
}
else {
cell = tableView.dequeueReusableCellWithIdentifier("idCellPeople", forIndexPath: indexPath) as! UITableViewCell
}
return cell
}
It’s quite easy to get the user’s basic profile data through the GIDSignIn singleton, don’t you think?
Now, if you run the application once again you’ll see that there’s no need to sign in again, as this will happen silently in the background. Besides that, when the ContentViewController view controller is presented, your basic info is displayed in the first section of the tableview.
Making an Authorized Request
Now that we’ve seen a basic usage of the GIDSignIn class, let’s go ahead to make an authorized request using the access token that the Sign-In button fetched using the OAuth 2.0 protocol. The first thing we’ll do here is to declare (and initialize at the same time) the following array which we’ll use as the datasource in the second section of the tableview:
var peopleDataArray: Array> = []
We’ll get the list of the Google+ circles’ people using the People.list method of the Google+ API. The details can be found in the documentation page of the People: list method, and you can even try the request on your own so you can see the results it brings back (make sure to switch on the toggle control right above the form).
Here are some sample results:
The request we are about to make is the following:
https://www.googleapis.com/plus/v1/people/USER_ID/people/COLLECTION?access_token=ACCESS_TOKEN
Besides the access token (last parameter), there are two other required parameters in the above request:
- The first one is the user ID that specifies the user for which we want to get the list of people in the Google+ circles. In this example we’ll use the special value me, so we get the people list of our own profile.
- The collection parameter is actually the collection of people we want to get, and it accepts either the visible or the connected value. Here we’ll use the first one, meaning that we’ll get all the people existing in the Google+ circles. The connected parameter value returns just the list of people who also use the same app to this one (so obviously it can’t be used).
We are going to define a custom function in the ContentViewController class that we’ll use to make the request. We’ll name it getPeopleList(). Just for the record I have to mention that you’ll find already implemented another method named performGetRequest(…) that performs the actual request in the starter project. We had discussed about it in the my previous tutorial regarding the YouTube API, and now we are reusing it.
Here’s the definition of the new function:
func getPeopleList() {
}
The logic we’ll follow is starting by specifying the request URL and providing the proper parameters. The last one of course is going to be the authentication access token. Then we’ll make the request, and if we get valid data back without any errors then we’ll proceed as follows (based always on the documentation and the sample results shown above):
- At first we’ll convert the JSON data into a dictionary object.
- Among all values in that dictionary, we’ll get an array called items. This one contains the people list.
- Each item of the items array is also a dictionary. From it we’ll get just two values, the displayName of each item, and the image URL string. Actually, that URL string exists into a sub-dictionary, named image.
- We’ll store the parsed data from each item into a new dictionary, and then this dictionary will be appended into in the peopleDataArray.
Let’s see the implementation:
func getPeopleList() {
let urlString = ("https://www.googleapis.com/plus/v1/people/me/people/visible?access_token=\(GIDSignIn.sharedInstance().currentUser.authentication.accessToken)")
let url = NSURL(string: urlString)
performGetRequest(url, completion: { (data, HTTPStatusCode, error) -> Void in
if HTTPStatusCode == 200 && error == nil {
let resultsDictionary = NSJSONSerialization.JSONObjectWithData(data!, options: nil, error: nil) as! Dictionary
// Get the array with people data dictionaries.
let peopleArray = resultsDictionary["items"] as! Array>
// For each item get the display name and download the picture.
// Store these values in a new dictionary, and then in the peopleDataArray array.
for item in peopleArray {
var dictionary = Dictionary()
dictionary["displayName"] = item["displayName"] as! String
let imageURLString = (item["image"] as! Dictionary)["url"] as! String
dictionary["imageData"] = NSData(contentsOfURL: NSURL(string: imageURLString)!)
self.peopleDataArray.append(dictionary)
}
// Reload the tableview data.
self.tblContent.reloadData()
}
else {
println(HTTPStatusCode)
println(error)
}
})
}
Pay attention to the way we access the authentication access token. The authentication property shown above and belongs to the GIDGoogleUser class (see the profile property), is actually an instance of the GIDAuthentication class, also part of the Sign-In SDK. The rest is easy and in accordance to what I described right before. Another interesting part regards the item image. As the only thing we have in the above parsing is the URL as a string value, we use it to grab the actual image data (NSData), which in turn is stored to the dictionary.
dictionary["imageData"] = NSData(contentsOfURL: NSURL(string: imageURLString)!)
Notice also the else case, where (for the sake of the tutorial) we display the error message and the HTTP status code in case of an unwanted situation.
Now, we’ll call the above function in the viewDidLoad:
override func viewDidLoad() {
...
getPeopleList()
}
Finally, let’s update the tableview methods. At first, let’s return the proper number of rows in the second section:
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if section == 0 {
return 2
}
else {
return peopleDataArray.count
}
}
Now the cell contents:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell: UITableViewCell!
if indexPath.section == 0 {
...
}
else {
cell = tableView.dequeueReusableCellWithIdentifier("idCellPeople", forIndexPath: indexPath) as! UITableViewCell
cell.textLabel?.text = peopleDataArray[indexPath.row]["displayName"] as? String
cell.imageView?.image = UIImage(data: peopleDataArray[indexPath.row]["imageData"] as! NSData)
}
return cell
}
We are ready to run the app once again now. This time you’ll see that the people in your Google+ circles are listed in the tableview:
[Image – t40_2_people_sample.png]
Signing Out and Disconnecting
So far we’ve managed to achieve two important goals: To sign in to the app using a Google account, and to perform an authorized request using the access token that was returned to the app as part of the results of the sign in process. However, we can’t still say that we’ve finished, as there’s no option to sign out yet. Apparently that’s what we’ll deal with in this part.
As the title above suggests, we are going to see two things here: How to sign out, and how to disconnect. Using the second option, users can totally disconnect their Google account from the app, while with the first option they just sign out from the app. Of course, in both cases the access and refresh tokens are revoked.
Focusing on our app again, there’s a toolbar with two bar button items in the ContentViewController scene regarding the features we want to implement here. Both button items have been connected to IBAction methods, so let’s see how to sign out first. Doing so it’s easy, as it’s just a matter of one line. Right next you’re given the respective IBAction method implementation:
@IBAction func signOut(sender: AnyObject) {
GIDSignIn.sharedInstance().signOut()
dismissViewControllerAnimated(true, completion: nil)
}
Note that at the end we dismiss the view controller. It would be totally unreasonable to let users have access to a protected area of the app while they have signed out.
If you want, you can test the above functionality. Note however that you have to provide your credentials again the next time you’ll launch the app after you’ve signed out.
Let’s go now to the disconnection. In this case, there’s no need to explicitly sign out users; It’s a process that takes place in the background automatically. Actually, disconnecting a Google account from the app is also just a matter of line, as shown next:
@IBAction func disconnect(sender: AnyObject) {
GIDSignIn.sharedInstance().disconnect()
}
Notice that we don’t dismiss the view controller here, and there’s a reason for that. If you remember, in the ViewController class we had defined the following delegate method, but there’s no code yet:
func signIn(signIn: GIDSignIn!, didDisconnectWithUser user: GIDGoogleUser!, withError error: NSError!) {
}
The above is called every time the disconnect() method of the GIDSignIn class is used, and any logic that comes right after the disconnection must be added at this point. In our case, we just want to dismiss the ContentViewController view controller after it’s been known that the disconnection has finished, but in order to manage this we need an instance of that class. So, let’s do that:
Initially, go back to the ViewController.swift file, and at the top of the class declare the following:
var contentViewController: ContentViewController!
Now, in the prepareForSegue(…) function we’ll instantiate the above object, and then we’ll use it in the previous delegate method:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "idSegueContent" {
contentViewController = segue.destinationViewController as! ContentViewController
}
}
And here’s the delegate method updated:
func signIn(signIn: GIDSignIn!, didDisconnectWithUser user: GIDGoogleUser!, withError error: NSError!) {
if let err = error {
println(error)
}
contentViewController.dismissViewControllerAnimated(true, completion: nil)
}
Notice that in case there’s any error we just print it in the console.
From the user’s perspective there’s no visible difference between the signing out and the disconnection process. However, the important thing is what happens behind the scenes.
Summary
Coming to the end, you see that the Google Sign-In button is a nice tool that can help you integrate Google authentication into an app at no time. If you’ve ever managed to implement the OAuth 2.0 protocol, then you can clearly understand the importance of that button; it lifts all the heavy work and the hassle from our shoulders, and it lets us focus to the really important stuff. The GIDSignIn class we met in the previous parts contains instances of other important classes as properties, and all of them provide us with all the information we need in order to make authorized requests. Besides that, in this post we also met a small part of the Google+ API, which, as I also said in the introduction, it was picked for our testing purposes only and not to learn about it in depth. Anyway, I hope all the information I gathered and presented here to show you the correct path if you’re about to integrate in your apps features similar to those we just saw. Generally, both this and the previous tutorial aim to teach you how to work with Google APIs by performing either authorized or unauthorized requests, so use that knowledge and focus on the APIs you like. It’s going to be really interesting!
For reference, you can download the final Xcode project here. Remember you’ll need to change the client IDs to your own before running the project.