Adding FB login into your iOS app
Prerequisites
- An FB account
A. Create an App in FB developer account
- Go to FB dev account (https://developers.facebook.com/)
- If you have no previous apps, click “Get Started”. Otherwise, click “My Apps”
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.)
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.
- 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.
2. Integrate FB Login to the iOS app
- Go to My Apps in FB dev account (https://developers.facebook.com/apps/)
- Select the created app
- Go to Facebook Login -> Quickstart menu on the left menu bar shown in the picture below
- Select iOS
(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)
- 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”
- 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.
- 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.
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