Facebook SSO in ios5

Go To StackoverFlow.com

4

I'm having issues with integrating facebook into my iOS app. When I launch my app, it redirects to the facebook app, which is good. But the auth dialog just vanishes from the screen (like a dismissed modal view controller), the delegate methods aren't firing, and I'm left in the facebook app instead of being redirected back to my app. I'm apparently not successfully initializing a session. I followed the steps in the iOS tutorial but I must have gone wrong somewhere. Most of the questions I've seen have been about errors or trying to get different behavior out of the auth dialog. If this is a dupe, please direct me to the identical question because I'm hitting a wall here. I have set up my .plist just as it says to in the tutorial. I used the bundle identifier for my app that I grabbed from iTunes connect. My constant kAppID is the AppID that I got from the Facebook Developer app interface. Having read through the headers and implementation files of the FB static lib, as well as FB's docs and tutorial, it seems to me that if all I want to do is redirect to FB app, sign in, and be redirected back to my own app, that these steps plus the code below should be sufficient.

In AppDelegate.m:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    kAppID = @"(this is where my app ID is)";
    // Override point for customization after application launch.
    facebook = [[Facebook alloc] initWithAppId:kAppID andDelegate:self];
    [facebook setSessionDelegate:self];
    return YES;
}

And in ViewController.m I grab a reference to that same instance of Facebook, and then call the following:

- (void)loginToFacebook:(id)sender {
    if ([defaults objectForKey:@"FBAccessTokenKey"] && [defaults objectForKey:@"FBExpirationDateKey"]) {
        facebook.accessToken = [defaults objectForKey:@"FBAccessTokenKey"];
        facebook.expirationDate = [defaults objectForKey:@"FBExpirationDateKey"];
    }
    if (![facebook isSessionValid]) {
        [facebook authorize:nil];
    }
}

Is there some gotcha that I'm not aware of? Or maybe I'm missing a critical step?

Oh, btw, Xcode 4.3.1, ios5SDK, iPhone 4S, ARC.

SS of .plist. enter image description here

AppDelegate.h:

#import <UIKit/UIKit.h>
#import "Facebook.h"
#import "FBConnect.h"

@interface AppDelegate : UIResponder <UIApplicationDelegate> {
    Facebook *facebook;
    NSUserDefaults *defaults;
    NSString *kAppID;
}

@property (strong, nonatomic) UIWindow *window;
@property (strong, nonatomic) Facebook *facebook;
@property (strong, nonatomic) id delegate;

@end

AppDelegate.m:

#import "AppDelegate.h"
#import "ViewController.h"

@implementation AppDelegate

@synthesize window = _window;
@synthesize facebook;
@synthesize delegate;

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    ViewController *viewController = [[ViewController alloc] init];
    kAppID = @"385380598149062";
    facebook = [[Facebook alloc] initWithAppId:kAppID andDelegate:viewController];

    return YES;
}

- (void)showSession {
    NSLog(@"FB Session: %@", [NSNumber numberWithBool:[facebook isSessionValid]]);
}

@end

As you can see, not much happens in these methods. The delegate class is the ViewController. All I really do in the AppDelegate is init the Facebook instance. On that note, herre's the whole ViewController.m (minus some non-facebook related stuff):

#import "ViewController.h"

@interface ViewController ()

@end

@implementation ViewController

@synthesize contacts, contactArray;

- (void)viewDidLoad
{
    [super viewDidLoad];
    defaults = [NSUserDefaults standardUserDefaults];
    AppDelegate *delegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
    facebook = delegate.facebook;
    [facebook setSessionDelegate:self];
    [self loginToFacebook:nil];
    eventsArray = [[NSMutableArray alloc] initWithObjects:@"Event one", @"Event two", nil];
}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
        return (interfaceOrientation = UIInterfaceOrientationPortrait);
    } else {
        return NO;
    }
}

- (void)loginToFacebook:(id)sender {
    if ([defaults objectForKey:@"FBAccessTokenKey"] && [defaults objectForKey:@"FBExpirationDateKey"]) {
        facebook.accessToken = [defaults objectForKey:@"FBAccessTokenKey"];
        facebook.expirationDate = [defaults objectForKey:@"FBExpirationDateKey"];
        NSLog(@"accessToken:%@\n expiry:%@", facebook.accessToken, facebook.expirationDate);
    }
    if (![facebook isSessionValid]) {
        [facebook authorize:nil];
    }
}

- (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url {
    NSLog(@"handle open url");
    return [facebook handleOpenURL:url];
}

- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation {
    return [facebook handleOpenURL:url];
}

- (void)request:(FBRequest *)request didLoad:(id)result {
    //ok so it's a dictionary with one element (key="data"), which is an array of dictionaries, each with "name" and "id" keys
    fbContacts = [(NSDictionary *)result objectForKey:@"data"];
    NSLog(@"Request did load");
    for (int i=0; i<[fbContacts count]; i++) {
        NSDictionary *friend = [fbContacts objectAtIndex:i];
        long long fbid = [[friend objectForKey:@"id"]longLongValue];
        NSString *name = [friend objectForKey:@"name"];
        NSLog(@"id: %lld - Name: %@", fbid, name);
    }
}

- (void)fbDidLogin {
    NSLog(@"FB did log in");
    [defaults setObject:[facebook accessToken] forKey:@"FBAccessTokenKey"];
    [defaults setObject:[facebook expirationDate] forKey:@"FBExpirationDateKey"];
    [defaults synchronize];
    [facebook requestWithGraphPath:@"me/friends" andDelegate:self];
}

- (void)fbDidNotLogin:(BOOL)cancelled {
    NSLog(@"FB login cancelled");
}

/**
 * Called after the access token was extended. If your application has any
 * references to the previous access token (for example, if your application
 * stores the previous access token in persistent storage), your application
 * should overwrite the old access token with the new one in this method.
 * See extendAccessToken for more details.
 */
- (void)fbDidExtendToken:(NSString*)accessToken
               expiresAt:(NSDate*)expiresAt {
    NSLog(@"FB extended token");
}

/**
 * Called when the user logged out.
 */
- (void)fbDidLogout {
    NSLog(@"FB logged out");
    [defaults removeObjectForKey:@"FBAccessTokenKey"];
    [defaults removeObjectForKey:@"FBExpirationDateKey"];
    [defaults synchronize];
}

/**
 * Called when the current session has expired. This might happen when:
 *  - the access token expired
 *  - the app has been disabled
 *  - the user revoked the app's permissions
 *  - the user changed his or her password
 */
- (void)fbSessionInvalidated {
    NSLog(@"FB session invalidated");
}
@end
2012-04-05 22:00
by geraldWilliam
Could you show what exactly you've done in .plist file? I think problem should be there.. - dmirkitanov 2012-04-05 22:06
edited, thanks for taking a look - geraldWilliam 2012-04-05 22:14
Hi. Could you post your appdelegate files?* - Alexander of Norway 2012-04-05 22:23
Hmm...When I try authorizing through safari, I get the auth dialog and then when I hit OK, it tries to go to https://m.facebook.com/dialog/permissions.request?refid=0 and I get a UIAlertView that says Safari cannot open the page because the address is invalid - geraldWilliam 2012-04-05 22:24


2

.plist looks great, maybe you just forgot about openurl handler?

- (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url {
    return [self.facebook handleOpenURL:url];
}

- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation {
    return [self.facebook handleOpenURL:url];
}

UPD:

  1. Just as an experiment, could you try this (from Hackbook example):

    // Now check that the URL scheme fb[app_id]://authorize is in the .plist and can
    // be opened, doing a simple check without local app id factored in here
    NSString *url = [NSString stringWithFormat:@"fb%@://authorize",kAppId];
    BOOL bSchemeInPlist = NO; // find out if the sceme is in the plist file.
    NSArray* aBundleURLTypes = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleURLTypes"];
    if ([aBundleURLTypes isKindOfClass:[NSArray class]] &&
        ([aBundleURLTypes count] > 0)) {
        NSDictionary* aBundleURLTypes0 = [aBundleURLTypes objectAtIndex:0];
        if ([aBundleURLTypes0 isKindOfClass:[NSDictionary class]]) {
            NSArray* aBundleURLSchemes = [aBundleURLTypes0 objectForKey:@"CFBundleURLSchemes"];
            if ([aBundleURLSchemes isKindOfClass:[NSArray class]] &&
                ([aBundleURLSchemes count] > 0)) {
                NSString *scheme = [aBundleURLSchemes objectAtIndex:0];
                if ([scheme isKindOfClass:[NSString class]] &&
                    [url hasPrefix:scheme]) {
                    bSchemeInPlist = YES;
                }
            }
        }
    }
    // Check if the authorization callback will work
    BOOL bCanOpenUrl = [[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString: url]];
    if (!bSchemeInPlist || !bCanOpenUrl) {
        UIAlertView *alertView = [[UIAlertView alloc]
                                  initWithTitle:@"Setup Error"
                                  message:@"Invalid or missing URL scheme. You cannot run the app until you set up a valid URL scheme in your .plist."
                                  delegate:self
                                  cancelButtonTitle:@"OK"
                                  otherButtonTitles:nil,
                                  nil];
        [alertView show];
        [alertView release];
    }
    

    At this step we will know, that it is all right with the URL scheme.

  2. Try to change [facebook authorize:nil]; with [facebook authorize:[[NSArray alloc] initWithObjects:@"read_friendlists", nil]]; so maybe SSO requires at least one permission to be specified.

2012-04-05 22:28
by dmirkitanov
no that stuff is there too. I suspect (based on what I found when I forced the authorization to go through Safari) that I'm passing an invalid URL to the FB auth dialog and that might be why we're not getting the authorization or returning to my app. The app is not available on the iTunes store (as it is in the early stages of development). This fact resulted in some kind of warning when registering the app with Facebook initially but then the warning went away and I figured we were good to go. I can't possibly need to have my app available on the store just to do this?!? - geraldWilliam 2012-04-05 22:33
Sorry, posted this before I saw it in ViewController.m code. No, afaik there is no difference whether your appstore id specified or not in app settings - dmirkitanov 2012-04-05 22:44
At facebook settings page, is "Configured for iOS SSO" checked? And in advanced settings, app type should be "Native/Desktop".. No more ideas right now - dmirkitanov 2012-04-05 22:52
Thanks very much. I did have the wrong thing ticked in advanced, so I changed that to Native/Desktop. It didn't help. I was already configured for iOS SSO. I'm at a loss. Thanks for your help though - geraldWilliam 2012-04-05 23:02
I am in fact getting the UIAlert from the code that you suggested I add. It goes to the FB app and doesn't redirect but if I exit FB and open my app the alert is there - geraldWilliam 2012-04-06 00:02
Ok, maybe it will help if you delete(!) app from device, then do clean up in Xcode, then try building it again (url scheme wasn't installed properly, something cached, etc.)? There should be a simple explanation : - dmirkitanov 2012-04-06 00:17
let us continue this discussion in chatgeraldWilliam 2012-04-06 00:36
I ended up having to re-do everything (delete from device, delete from app store, delete from FB) and just set it all up all over again. The Hackbook check was a great suggestion and definitely helpful. I got it all going, finally. Thank you so much for your help - geraldWilliam 2012-04-16 19:16
Damn. I'm in the same boat and can't figure this damn thing out. I've tried it on a few test apps and they all do the same thing too. FB drives me nuts - crewshin 2012-07-05 18:32


2

I had the same problem, I was redirected to the facebook app and the auth dialog was dismissed immediately leaving me in the facebook app.

The problem was in the .plist, I forgot to enter fb before the appID number in the URL Schemes.

plist

if your delegate methods still aren't firing it's because you have to put all the facebook logic in your application's delegate. I also enabled the stuff aurav aka sparsh said above.

2012-07-21 15:40
by DagonAmigaOS
SO THANKFUL you posted this - jmosesman 2012-08-20 05:01


0

After struggling for long time finally got a solution for this problem, I dont its correct but its working like charm for my App:

go to developer.facebook.com

Select your app from list (App which app is your are using in URL scheme)

If your app is selected as native app then it will ask for bundle identifiers

provide him bundle identifier by using which you are building your app

if your using wildcard bundle identifier then provide like com.product.abc otherwise provide full bundle identifier.

and your FB login will start working for you.your settings must be like as shown in image

2012-07-10 11:31
by Gaurav
Ads