Facebook login using the iOS API with Swift

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

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.
  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.
  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.
  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.

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.

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:

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

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:

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.

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).

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

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:

  • A UIView in the shape of a button, with the class name set to FBSDKLoginButton, connected to a class outlet named loginButton
  • A UIView in the shape of a square profile photo, with the class name set to FBSDKProfilePictureView. No class outlet is needed.
  • A UILabel, with a class outlet named userIdLabel
  • A UILabel, with a class outlet named userNameLabel

In the storyboard, the form looks like so:

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)
  • The first line sets this ViewController as the delegate for the Facebook login events
  • The second line lets the FB login process know what read permissions we’re asking the user to approve
  • The third line asks the SDK to send a notification if/when the user’s profile changes.

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.

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.

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:

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.

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.

And that’s it!

Swift 3.0 substrings made easy

Swift is a fantastic, modern language, and has fast become my favorite. So much of what’s built into it is intuitive, simple and makes coding much more expressive than older, more syntactically heavy programming languages.

Swift is a fantastic, modern language, and has fast become my favorite. So much of what’s built into it is intuitive, simple and makes coding much more expressive than older, more syntactically heavy programming languages.

But…sometimes its sophistication makes what was simple in older languages more complicated. Case in point is taking substrings. Substrings are not difficult to deal with in Swift, but personally I find the syntax confusing. Many others do as well, and it’s common to address the confusion with an extension pattern.

Let’s first look at some basics of how to take substrings “out of the box”, and then look at a pretty common extension approach to make the substring syntax more approachable and simple.

The Range Construct

The foundation of taking substrings in Swift is using Range objects. Range is just what it sounds like — an encapsulation of a beginning and ending index within a String.

Take a look at he following quick example. In the example, the .range function is used to get the start and end index of the word “quick” within the larger string. Then, if the range is not nil, that word is extracted using the range bounds, and printed to the console.

This is something we might do in real life, and the Swift syntax is expressive and simple to remember.

// find and return a substring using Swift 3.0 let sentence = "The quick brown fox jumped over the lazy dog." if let quick = sentence.range(of: "quick") { let word = sentence[quick.lowerBound..<quick.upperBound] print(word) // prints "quick" }

The Range syntax is used to extract strings by known index as well, but in this case the syntax really gets in the way and is not simple or easy to read.

Before getting into it, let’s review how this would be done in C++:

// find and return a substring at known location using C++ string sentence = "The quick brown fox jumped over the lazy dog."; string word = sentence.Substring(4, 5); cout << word; // prints "quick"

The C++ is syntactically simple and easy to understand. Substring just starts at the fifth character, and extracts five characters. Simple.

Swift is similar to the C++ standard library conceptually, but the use of the Range construction. This results in a significantly more verbose statement to accomplish what is simple to do in C++:

let sentence = "The quick brown fox jumped over the lazy dog." let substringNoExtension = sentence[sentence.index(sentence.startIndex, offsetBy: 4)...sentence.index(sentence.startIndex, offsetBy: 8)] print(substringNoExtension) // prints "quick"

The syntax is actually quite similar to the C++ version, but let’s face it — it’s long and tedious. The interpretation is “extract from the string from index 4 to index 8 inclusive”. OK, simple concept, but wow! Look at all that syntax. If you need to do this once, not a problem, but what if the code uses offsets frequently?

Swift using an Extension

Luckily, Swift has the concept of extensions which allow us to essentially append new methods and data to existing classes and structs — even ones where we don’t have the source code or aren’t allowed to inherit new objects from them.

So first, let’s add an extension that adds a subscript operator that accepts a closed range:

extension String { subscript(range: ClosedRange<Int>) -> String { let lowerIndex = index(startIndex, offsetBy: max(0,range.lowerBound), limitedBy: endIndex) ?? endIndex return substring( with: lowerIndex..<(index(lowerIndex, offsetBy: range.upperBound - range.lowerBound + 1, limitedBy: endIndex) ?? endIndex)) } }

OK, so yes, I know…this is a lot of code too. But remember, this is an extension, and you just need to add this extension method to global scope one time, then use it over and over wherever you need it.

Now with the extension added to global scope, the substring with known indexes becomes the following:

let sentence = "The quick brown fox jumped over the lazy dog." let substringWithExtension = sentence[4...8] print(substringWithExtension) // prints "quick"

This syntax is even simpler than the original C++, and it’s immediately intuitive that we’re taking a range of characters from the 4th to the 8th character.

Simple!

Full Extension Example

Below is a more complete extension to add a somewhat more complete substring extension to String which builds on the simple single example above.

extension String { subscript(i: Int) -> String { guard i >= 0 && i < characters.count else { return "" } return String(self[index(startIndex, offsetBy: i)]) } subscript(range: Range<Int>) -> String { let lowerIndex = index(startIndex, offsetBy: max(0,range.lowerBound), limitedBy: endIndex) ?? endIndex return substring(with: lowerIndex..<(index(lowerIndex, offsetBy: range.upperBound - range.lowerBound, limitedBy: endIndex) ?? endIndex)) } subscript(range: ClosedRange<Int>) -> String { let lowerIndex = index(startIndex, offsetBy: max(0,range.lowerBound), limitedBy: endIndex) ?? endIndex return substring(with: lowerIndex..<(index(lowerIndex, offsetBy: range.upperBound - range.lowerBound + 1, limitedBy: endIndex) ?? endIndex)) } }