Sign up for a Parse account to implement this tutorial and more!

Sign Up

Icon_facebook_ios
Integrating Facebook in iOS

Learn how to use Parse with the Facebook SDK to create a profile viewer application. This tutorial will teach you how to create and login Parse users through Facebook and make queries to the Facebook Graph API.

iOS
Facebook
PFUser

Download code for this tutorial:

.zip File GitHub

Parse makes it very easy for you to quickly add user accounts to your application using the PFUser object. But, if you want to integrate your application with Facebook, it can be challenging to manage two sets of users. The Facebook SDK can be used with Parse's SDK, and is integrated with the PFUser class to make linking your users to their Facebook identities easy.

This tutorial will guide you through the creation of a simple iOS application that allows a user to log in via Facebook and view their profile information. It consists of two view controllers. The LoginViewController has a single button that allows the user to log in, and the UserDetailsViewController presents the user's profile information in a UITableView. You can download the Xcode project from the link above.

Prerequisites

To start using Facebook with Parse, you need to:

Setup

We'll start by configuring the application for use with Parse and Facebook. First, add your Parse application and client keys in the app delegate. Then, select your project file and navigate to the "Info" tab. Add a new key for FacebookAppID under "Custom iOS Target Properties" with your Facebook app's ID as a string value. Next you will need to add a "URL Type" to your project. Using the "Add" button on the bottom left, select "Add URL Type". You should see a new URL Type called "untitled". Expand it and set the URL Scheme field to "fbYour_App_Id" (ex. fb1234567890).

Now that all of the keys are in place, we need to add a few methods to the app delegate to support Facebook Login.

- (BOOL)application:(UIApplication *)application 
            openURL:(NSURL *)url
  sourceApplication:(NSString *)sourceApplication
         annotation:(id)annotation {
    return [FBAppCall handleOpenURL:url
                  sourceApplication:sourceApplication
                        withSession:[PFFacebookUtils session]];
}
 
- (void)applicationDidBecomeActive:(UIApplication *)application {
    [FBAppCall handleDidBecomeActiveWithSession:[PFFacebookUtils session]];
}

- (void)applicationWillTerminate:(UIApplication *)application {
    [[PFFacebookUtils session] close];
}

Login

When you use the Parse framework to log in a new user through Facebook, a User object is also created and stored for you in Parse. You are still able to set and retrieve data as you would with a regular PFUser object, but you also have access to the entire Facebook API. In the loginButtonTouchHandler: method within the LoginViewController we can log in the user as follows. If you’ve used the PFUser object before, this should look very familiar, except that you're making a call to PFFacebookUtils.

- (IBAction)loginButtonTouchHandler:(id)sender  {
    // Set permissions required from the facebook user account
    NSArray *permissionsArray = @[ @"user_about_me", @"user_relationships", @"user_birthday", @"user_location"];

    // Login PFUser using Facebook
    [PFFacebookUtils logInWithPermissions:permissionsArray block:^(PFUser *user, NSError *error) {
        [_activityIndicator stopAnimating]; // Hide loading indicator

        if (!user) {
            NSString *errorMessage = nil;
            if (!error) {
                NSLog(@"Uh oh. The user cancelled the Facebook login.");
                errorMessage = @"Uh oh. The user cancelled the Facebook login.";
            } else {
                NSLog(@"Uh oh. An error occurred: %@", error);
                errorMessage = [error localizedDescription];
            }
            UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Log In Error"
                                                            message:errorMessage
                                                           delegate:nil
                                                  cancelButtonTitle:nil
                                                  otherButtonTitles:@"Dismiss", nil];
            [alert show];
        } else {
            if (user.isNew) {
                NSLog(@"User with facebook signed up and logged in!");
            } else {
                NSLog(@"User with facebook logged in!");
            }
            [self _presentUserDetailsViewControllerAnimated:YES];
        }
    }];

    [_activityIndicator startAnimating]; // Show loading indicator until login is finished
}

- (void)_presentUserDetailsViewControllerAnimated:(BOOL)animated {
    UserDetailsViewController *detailsViewController = [[UserDetailsViewController alloc] initWithStyle:UITableViewStyleGrouped];
    [self.navigationController pushViewController:detailsViewController animated:animated];
}

Notice that we create a permissions array. This indicates what data we want to access once the user is logged in. The full list can be found on the Facebook developer website.

Requesting and Setting User Data

Now that the user is logged in, we can start making requests to the Facebook Graph API. To make our request as soon as the view is displayed, we add this code to the UserDetailsViewController's viewDidLoad method.

- (void)viewDidLoad {
    // ...
    [self _loadData];
}

- (void)_loadData {
    // ...
    FBRequest *request = [FBRequest requestForMe];
    [request startWithCompletionHandler:^(FBRequestConnection *connection, id result, NSError *error) {
        // handle response
    }];
}

The _loadData method creates a request for Facebook data then sends the request to Facebook. The user's Facebook access token will be automatically added to the request, so a "me"-based request path will return the current user's data.

To handle the reply from the graph request, we can parse through the received data inside the FBRequest completion handler. We can use this response to populate the appropriate UI elements.

- (void)_loadData {
    // ...
    FBRequest *request = [FBRequest requestForMe];
    [request startWithCompletionHandler:^(FBRequestConnection *connection, id result, NSError *error) {
        if (!error) {
            // result is a dictionary with the user's Facebook data
            NSDictionary *userData = (NSDictionary *)result;

            NSString *facebookID = userData[@"id"];
            NSString *name = userData[@"name"];
            NSString *location = userData[@"location"][@"name"];
            NSString *gender = userData[@"gender"];
            NSString *birthday = userData[@"birthday"];
            NSString *relationship = userData[@"relationship_status"];

            NSURL *pictureURL = [NSURL URLWithString:[NSString stringWithFormat:@"https://graph.facebook.com/%@/picture?type=large&return_ssl_resources=1", facebookID]];
 
            // Now add the data to the UI elements
            // ...
        }
    }];
}

Setting the Profile Picture

In the Facebook Graph API request we made above, we also obtained the id field. This is the user's Facebook id. We can use it to create a URL that points to the user's profile picture. To display this picture, we download it then set the image once the download successfully completes. We can do this in the same completion handler from above as follows:

// URL should point to https://graph.facebook.com/{facebookId}/picture?type=large&return_ssl_resources=1
NSURL *pictureURL = [NSURL URLWithString:[NSString stringWithFormat:@"https://graph.facebook.com/%@/picture?type=large&return_ssl_resources=1", facebookID]];

NSURLRequest *urlRequest = [NSURLRequest requestWithURL:pictureURL];

// Run network request asynchronously
[NSURLConnection sendAsynchronousRequest:urlRequest
                                   queue:[NSOperationQueue mainQueue]
                       completionHandler:
    ^(NSURLResponse *response, NSData *data, NSError *connectionError) {
        if (connectionError == nil && data != nil) {
            // Set the image in the header imageView
            self.headerImageView.image = [UIImage imageWithData:data];
        }
}];

Logout

Logging out a Facebook PFUser is no different than logging out a regular PFUser. We can statically call logOut on the PFUser object.

- (void) logoutButtonAction:(id)sender  {
    [PFUser logOut]; // Log out

    // Return to Login view controller
    [self.navigationController popToRootViewControllerAnimated:YES]; 
}

Keeping the User Logged-in

Using the code above, a user would need to log in every time they opened the app. This is because the Facebook session information is not stored between launches. Caching this information can be a confusing ordeal, but Parse makes this very easy by automatically saving the session information in the currentUser object. To keep a user logged in, we need to follow two simple steps. We start by adding the mechanism to bypass the login screen when a cached user is identified and finally ensuring that a user is automatically logged out if the cached session is invalidated (ex. if the password changes).

Bypassing the Login

After a user logs in, Parse will automatically cache the Facebook and Parse sessions in the currentUser object. We simply need to bypass the login screen if a user is currently cached. In our application, we'll perform this check at the end of the viewWillAppear: method of LoginViewController. When we find a cached user session, we simply push the next view controller.

- (void)viewWillAppear:(BOOL)animated {
    ...
    if ([PFUser currentUser] && // Check if user is cached
        [PFFacebookUtils isLinkedWithUser:[PFUser currentUser]]) { // Check if user is linked to Facebook
        // Present the next view controller without animation
        [self _presentUserDetailsViewControllerAnimated:NO];
    }
}

Handling an Invalidated Session

We cannot know if the cached Facebook session is valid until we attempt to make a request to the API. A session can become invalidated if a user changes their password or revokes the application's privileges. When this happens, the user needs to be logged out. We can identify an invalid session error within a FBRequest completion handler and automatically log the user out.

FBRequest *request = [FBRequest requestForMe];
[request startWithCompletionHandler:^(FBRequestConnection *connection, id result, NSError *error) {
    if (!error) {
        // handle successful response
    } else if ([[[[error userInfo] objectForKey:@"error"] objectForKey:@"type"]
               isEqualToString: @"OAuthException"]) { // Since the request failed, we can check if it was due to an invalid session
        NSLog(@"The facebook session was invalidated");
        [self logoutButtonAction:nil];
    } else {
        NSLog(@"Some other error: %@", error);
    }
}];

The application should now be able to log in Parse users through Facebook, display their profile information, log them out and make use of the cached user session. Feel free to download the Xcode project and experiment with the example.