www.robkerr.com
www.robkerr.com

mobile development, cloud computing and building great software

Rob Kerr
Author

Addicted to coding since writing my first programs for the Commodore computers in the 1980s. Currently working as an independent contractor focused on native iOS development.

Share


Tags


Twitter


www.robkerr.com

Facebook login using the iOS API with Swift

Rob KerrRob Kerr

A common requirement for consumer mobile apps is to allow users to authenticate with their FaceBook credentials. Let's explore why, and then go ahead and make the integration with iOS and Swift

Why use Facebook authentication?

Why would we want to use Facebook auth instead of providing our own authentication database? Really it boils down to two reasons:

  1. Easier user experience. If we let users use their Facebook accounts to authenticate to our application, they don't need to remember a new user id and password, and are more likely to go ahead and use our app because it's a frictionless experience.

  2. Easier and more secure for our app. Since we're effectively "outsourcing" identity to Facebook, we don't need to manage/secure user passwords, implement password reset processes and so on.

Overall Process

Here's the overall process of integrating Facebook Identity:

  1. Register our app on Facebook. This lets Facebook know who we are, when authentication requests come to their API. In the setup process we'll also communicate which Facebook services we're going to use. Some of the services we can integrate into our app require additional Facebook review of us. But the basic authentication in this post does not.

  2. Integrate the Facebook API into our XCode project. Just like any integration, we'll need to add some frameworks. In this project I'll be using CocoaPods to download and install the Facebook frameworks.

  3. Add a button to the app UI to initiate the Facebook request. This can be done in code or in storyboard design. I'll use the storyboard method.

  4. Capture the Facebook user ID, and insert it into our own web service database so we can associate the Facebook users with one of our users.

Register with Facebook

Facebook provides a Quick Start for iOS tool to create app IDs, which I'll be using.

  1. On the Quick Start form, provide a display name for the new App, adn then click on the Create New Facebook App ID button.

New Facebook Name

  1. The next step is to provide a contact e-mail and an application category. After providing this info, click the Create App ID button.

Email and Category

  1. From here, the Facebook Quick Start screens are providing us some great step-by-step instructions what to do next. Capture the information about the info.plist contents, which we'll later add to our app.

Info Content

  1. Mid-way down this form is a switch to indicate whether the app we're creating contains in-app purchases. The default is Yes, so if your app doesn't include them (or if you don't want to use FB to track them), slide this button to the No position.

in app purchase

Finally--and this may be the most important step!--provide the Bundle Identifier for the app to Facebook. When our app makes calls to the FB API, it will send the Bundle ID, which FB will use to match our app to the App ID record we just created within FB.

bundle id

Adding the Facebook API to our XCode Project

Next up, we need to add the Facebook API to our XCode project. This can be done by downloading the Facebook frameworks and manually integrating them, but I always find using CocoaPods more productive and a better way to keep 3rd-party modules up-to-date over time.

Install CocoaPods

If you're not familiar with CocoaPods, it's a Ruby-based package manager that modifies your XCode project to include 3rd-party modules (like the Facebook API). CocoaPods will configure an XCode workspace that includes your project, and additional projects for the 3rd-party components.

If you don't have CocoaPods installed on your development workstation, or don't know what it is, browse over to https://cocoapods.org to learn about it and install it before continuing.

Create the Podfile

After creating your base XCode project, open a bash shell in the same folder where your .xcodeproj is located, and then run the following command to create a new Podfile

$ pod init

Next edit the Podfile (I'm using nano, but you can use any text editor). Update the new Podfile to look as follows:

Podfile

At this point, your project folder should look something like this:

Podfile created

After updating the Podfile, make sure XCode is closed, and then run a the following command to download the Facebook frameworks and configure your XCode workspace:

$ pod install

Once the frameworks are installed and the .xcworkspace is created, your folder should now look like this:

Pods Installed

From this point, you should never have a reason to open your .xcodeproj project, and from now on always open the .xcworkspace file instead. The Facebook API frameworks will be new projects in the workspace, referenced by your original project while editing and building the project.

Update the .plist file

Back in step 1, Facebook gave us text to add to our .plist file, so open the .xcworkspace, and then open the .plist file as text (so we can paste in the entries FB gave us).

edit plist as source

Add the entries from the Facebook Quick Start screen before the closing </dict> tag.

Added info entries

Setup the AppDelegate

Two methods to update int he AppDelegate class. The first is our old friend application : didFinishLaunchingWithOptions. In this method, just add a call to pass on the launch parameters to the Facebook API:

FBSDKApplicationDelegate.sharedInstance().application(application,
     didFinishLaunchingWithOptions: launchOptions)

Next, add the delegate method application : open url, and fill it out with a similar call that passes on to Facebook API:

func application(_ app: UIApplication, open url: URL, 
                  options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool {
    let sourceApplication: String? = options[UIApplicationOpenURLOptionsKey.sourceApplication] as? String

    return FBSDKApplicationDelegate.sharedInstance().application(app, open: url, sourceApplication: sourceApplication, annotation: nil)
} 

With these changes, the AppDelegate will make calls to the Facebook API when initially launched (didFinishLaunchingWithOptions method), and when launched after the Facebook login is completed (open url method).

Configure the UI

Since this is a test application, I've created it as a simple single view app. In the default storyboard, I've added the following controls:

In the storyboard, the form looks like so:

Storyboard

Add code to the ViewController

There's not much code involved in making this login button work. Its presence on the form is enough to enable it. The code we add really is just to set a couple properties, and add delegate methods that are called as the user interacts with the Facebook login process.

Add the Import

import FBSDKLoginKit

Declare our class with the delegate protocol

class ViewController: UIViewController, FBSDKLoginButtonDelegate {

Connect Outlets

@IBOutlet weak var loginButton: FBSDKLoginButton!
@IBOutlet weak var userIdLabel: UILabel!
@IBOutlet weak var userNameLabel: UILabel!

Configure the button

In the ViewDidLoad method, add the following configuration lines:

loginButton.delegate = self
loginButton.readPermissions = ["public_profile", "email", "user_friends"]
FBSDKProfile.enableUpdates(onAccessTokenChange: true)

Create a profile change listener

Just below the button configuration lines, add the following code to receive a notification when the user's profile is updated (asynchronously) after the login completes.

NotificationCenter.default.addObserver(
    forName: NSNotification.Name.FBSDKProfileDidChange, 
    object: nil, queue: nil) { (Notification) in

    if let profile = FBSDKProfile.current(),
        let firstName = profile.firstName,
        let lastName = profile.lastName {
        self.userNameLabel.text = "\(firstName) \(lastName)"
    } else {
        self.userNameLabel.text = "Unknown"
    }
}

The listener is needed because the profile won't be completely populated at the moment the login completes. So effectively this code will wait around for the API to complete the profile, then will be called.

Implement FBSDKLoginButtonDelegate protocol methods

After the user interacts with Facebook to login, we'll be notified when the login is completed, and if the user presses the button again to logout.

func loginButton(_ loginButton: FBSDKLoginButton!, 
          didCompleteWith result: FBSDKLoginManagerLoginResult!,
           error: Error!) {
                   if let result = result {
                       self.userIdLabel.text = result.token.userID
                       // Notify our web API that this user has logged in with Facebook
                   }
}

func loginButtonDidLogOut(_ loginButton: FBSDKLoginButton!) {
    print("Logging out")
}

With these methods implemented, the application is complete.

If using Simulator, Turn Keychain Sharing on

If you don't need to test using a simulator, and will use a physical device for testing, proceed to the next section -- you're good to go.

However, if you want to run this application on a simulator and connect to Facebook, there's one more small thing to do -- enable Keychain Sharing for your target.

Enable Keychain Sharing

Select your target, and in the Capabilities tab, slide the Keychain Sharing switch to the "On" position. Similar to the below (image credit:

Running the application

When we run this application, the first thing we see is the main form, with the login button waiting to be pressed:

Login Waiting Button

After pressing the login button, the application will be put in background while Safari launches to ask the user to login within the Facebook mobile experience. In this screen I'm informed that I've already authorized this app once, so I only have to confirm that I still want to login.

Facebook Login

After I finish with Facebook, I'm transferred again back to AppDelegate, within that open url method we implemented earlier. Afterward, the form is shown again, this time with my profile photo, name and Facebook ID.

Logged in

And that's it!

Rob Kerr
Author

Rob Kerr

Addicted to coding since writing my first programs for the Commodore computers in the 1980s. Currently working as an independent contractor focused on native iOS development.

Comments