Adding FB login into your iOS app

Kulakshi Fernando
6 min readOct 3, 2020

--

Prerequisites

  • An FB account

A. Create an App in FB developer account

  1. Go to FB dev account (https://developers.facebook.com/)
  2. If you have no previous apps, click “Get Started”. Otherwise, click “My Apps”
Go to Get Started (or My Apps) in FB dev account to create a new app

3. Go forward in the windows coming up until there is a “Create App” or “Create First App” button. Click this button to create an app.

4. Select the purpose of your app and click next.

5. Provide the app name and a contact email, and finally click “Create App ID”. (You will have to go through a ReCaptcha.)

Create a new App in FB dev account

B. Integrating FB login in iOS app — with Objective C

(If you already have an app, please skip the first step)

Note: This article is written using Xcode Version 11.7 (11E801a) and Objective C.

  1. Create a new app (Detailed source: https://developer.apple.com/documentation/xcode/creating_an_xcode_project_for_an_app?language=objc)
  • Go to Xcode. Click File -> New -> Project)
  • Select “Single View App” and click “Next”
  • Give a product name and other details (More details about this can be found in the link mentioned above) and click “Next” to create the project.
Give a product name and other details to create an Xcode app

2. Integrate FB Login to the iOS app

Go to Facebook Login -> Quickstart
  • Select iOS
Select iOS from quickstart

(Now all the details you need are available on the page given by FB. I will anyway show all steps for the sake of completeness.)

  • Select the development environment (Here, I’m using FB SDK)
Select the development environment
  • Download the FB SDK, and add it as told in the FB dev page. (Here, the “Bolts” framework is mentioned in the list of frameworks that should be added, but it is not present in the downloaded SDK. You can ignore it). Add the Carthage/Build/iOS/FBSDKLoginKit.framework and Carthage/Build/iOS/FBSDKCoreKit.framework into the Framework group of your Xcode Project. Then click “Next” to go to the second step on the FB Dev page.

Note: I encountered “dyld: Library not loaded: @rpath/FBSDKLoginKit.framework/FBSDKLoginKit” later when trying to run the project after adding code relevant to FB login. In order to prevent that go to the General tab of the project target, and change the embedded status of linked frameworks above into “Embed & Sign”

Linking FB frameworks
  • Add your Bundle ID, save it and press Continue.
  • If you prefer single sign in, Switch it on and move to the next step.
  • Update the info.plist as mentioned. The file info.plist can be opened up in edit mode as shown below.
open info.plist on edit mode
  • Copy and add the code given into AppDelegate.m and SceneDelegate.m files. To make your life easy, I’m adding my code here.
// AppDelegate.m file#import "AppDelegate.h"
#import <FBSDKCoreKit/FBSDKCoreKit.h>
@interface AppDelegate ()
@end
@implementation AppDelegate- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[[FBSDKApplicationDelegate sharedInstance] application:application
didFinishLaunchingWithOptions:launchOptions]; //this line is added for FB login integration

return YES;
}
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url options:(nonnull NSDictionary<UIApplicationOpenURLOptionsKey, id> *)options{ [[FBSDKApplicationDelegate sharedInstance] application:application openURL:url options:options]; //this line is added for FB login integration return YES;
}

//rest of the app delegate
...
@end// SceneDelegate.m file#import "SceneDelegate.h"
#import <FBSDKCoreKit/FBSDKCoreKit.h>
#import <FBSDKLoginKit/FBSDKLoginKit.h>
@interface SceneDelegate ()
@end
@implementation SceneDelegate//Following method is added to integrate FB login- (void)scene:(UIScene *)scene openURLContexts:(NSSet<UIOpenURLContext *> *)URLContexts{ UIOpenURLContext *context = URLContexts.allObjects.firstObject;
[FBSDKApplicationDelegate.sharedInstance application:UIApplication.sharedApplication openURL:context.URL sourceApplication:context.options.sourceApplication annotation:context.options.annotation];
}//rest of the scene delegate
...
@end
  • Update UI to add the FB login button. I have a single screen yet in my application and its name is “ViewController”
//  ViewController.m#import "ViewController.h"
#import <FBSDKCoreKit/FBSDKCoreKit.h>
#import <FBSDKLoginKit/FBSDKLoginKit.h>
@interface ViewController ()
@end
@implementation ViewController- (void)viewDidLoad {
[super viewDidLoad];
FBSDKLoginButton *loginButton = [[FBSDKLoginButton alloc] init]; // Optional: Place the button in the center of your view.
loginButton.center = self.view.center;
[self.view addSubview:loginButton];
}
@end

Ok, all done! Now if you run your project following screen should appear.

FB login in iOS app

Note: In order to test FB login in developer mode, you have to add test users in FB dev account under your app (https://developers.facebook.com/docs/apps/test-users/).

C. Getting the required data from FB to be used in our app

Now that we can log in to FB, we should be able to get details of the user that we need to use in our app. So in this app, I expect to get a unique user id to identify the user, user name, user email, and user profile picture.

In order to get the user email and the profile picture, we need to get permission for it at the login. So add the following line of code before logging in,

loginButton.permissions = @[@"public_profile", @"email"];

Now, in order to detect when a user logged in, we can use the FBSDKLoginButtonDelegate. Implement the view controller class you use for login by FBSDKLoginButtonDelegate.

//ViewController.h file#import <UIKit/UIKit.h>
#import <FBSDKLoginKit/FBSDKLoginKit.h>
@interface ViewController : UIViewController <FBSDKLoginButtonDelegate>
@end

Don’t forget to assign an object of this class as the delegate of FBSDKLoginButton.

loginButton.delegate = self;

Now we can use loginButton:didCompleteWithResult:error: method to detect the callback event from FB after the login process.

Note: I had to override the loginButtonDidLogOut: method because otherwise, the app encountered a run time error for not having this method.

- (void)loginButton:(FBSDKLoginButton *)loginButton didCompleteWithResult:(FBSDKLoginManagerLoginResult *)result error:(NSError *)error{   if(result){
if(!result.isCancelled){
NSLog(@"FB token %@", result.token.tokenString);
NSLog(@"FB userID %@", result.token.userID);
NSLog(@"FB appID %@", result.token.appID);
}
}
if(error){
NSLog(@"Error: %@", error);
}
}
- (void)loginButtonDidLogOut:(FBSDKLoginButton *)loginButton{
}

If the user did not cancel the login process, or any other error did not occur, we will get basic authentication details and user ID as the result of the login process.

Well, now that we have the user ID, we can use that to get the user name, email, and profile picture with FB Graph API.

(All the fields of the user that are accessible via Graph API are listed here: https://developers.facebook.com/docs/graph-api/reference/user/)

So here goes the complete code of my ViewController.m file along with getting user details mentioned above.

//  ViewController.m#import "ViewController.h"
#import <FBSDKCoreKit/FBSDKCoreKit.h>
#import <FBSDKLoginKit/FBSDKLoginKit.h>
@interface ViewController ()
@end
@implementation ViewController- (void)viewDidLoad {
[super viewDidLoad];
FBSDKLoginButton *loginButton = [[FBSDKLoginButton alloc] init];
loginButton.permissions = @[@"public_profile", @"email"];
loginButton.delegate = self;
loginButton.center = self.view.center; //optional
[self.view addSubview:loginButton];
}
- (void)loginButton:(FBSDKLoginButton *)loginButton didCompleteWithResult:(FBSDKLoginManagerLoginResult *)result error:(NSError *)error{
if(!error){
if(!result.isCancelled){
if ([FBSDKAccessToken currentAccessToken]) {
[[[FBSDKGraphRequest alloc] initWithGraphPath:@"/me/" parameters:nil] startWithCompletionHandler:^(FBSDKGraphRequestConnection *connection, id result, NSError *error) {
if (!error) {
NSLog(@"fetched user: %@", result);
NSLog(@"fetched user name: %@",result[@"name"]);
}else{
NSLog(@"fetched user name error:%@", error);
}
}];

[[[FBSDKGraphRequest alloc] initWithGraphPath:[NSString stringWithFormat:@"me?fields=picture",result.token.userID] parameters:nil HTTPMethod:@"GET"]
startWithCompletionHandler:^(FBSDKGraphRequestConnection *connection, id result, NSError *error) {
if (!error) {
NSLog(@"fetched user picture: %@", result);
NSLog(@"fetched user picture url: %@", result[@"picture"][@"data"][@"url"]);
}else{
NSLog(@"fetched user picture error:%@", error);
}
}];

[[[FBSDKGraphRequest alloc] initWithGraphPath:[NSString stringWithFormat:@"me?fields=email",result.token.userID] parameters:nil HTTPMethod:@"GET"]
startWithCompletionHandler:^(FBSDKGraphRequestConnection *connection, id result, NSError *error) {
if (!error) {
NSLog(@"fetched user email: %@", result);
}else{
NSLog(@"fetched user email error:%@", error);
}
}];
}
}
}
else{
NSLog(@"Error: %@", error);
}
}
-(void) getFBUserDetails{}- (void)loginButtonDidLogOut:(FBSDKLoginButton *)loginButton{}@end

As the last step, we can check whether the user has already logged in at first and add the login button only otherwise.

- (void)viewDidLoad {
[super viewDidLoad];
FBSDKLoginButton *loginButton = [[FBSDKLoginButton alloc] init];
loginButton.permissions = @[@"public_profile", @"email"];
loginButton.delegate = self;
//check whether the user has already logged in
if ([FBSDKAccessToken currentAccessToken]) {
[self getFBUserDetails]; //a method written with previously mentioned code for getting user details
}else{
loginButton.center = self.view.center;
[self.view addSubview:loginButton];
}
}

So we are done. You can find the full code here: https://github.com/Kulakshi/FBLoginiOSTest

--

--