diff --git a/samples/BooleanOGSample/BooleanOGSample/BOGAppDelegate.m b/samples/BooleanOGSample/BooleanOGSample/BOGAppDelegate.m index ea00b3fab1..c5f65a7226 100644 --- a/samples/BooleanOGSample/BooleanOGSample/BOGAppDelegate.m +++ b/samples/BooleanOGSample/BooleanOGSample/BOGAppDelegate.m @@ -67,7 +67,9 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:( // We create and open a session at the outset here; if login is cancelled or fails, the application ignores // this and continues to provide whatever functionality that it can NSArray *permissions = [NSArray arrayWithObjects:@"publish_actions", nil]; - [FBSession sessionOpenWithPermissions:permissions completionHandler:nil]; + [FBSession openActiveSessionWithPermissions:permissions + allowLoginUI:YES + completionHandler:nil]; return YES; } diff --git a/samples/JustRequestSample/JustRequestSample/JRViewController.m b/samples/JustRequestSample/JustRequestSample/JRViewController.m index b49de4c465..b327dc6333 100644 --- a/samples/JustRequestSample/JustRequestSample/JRViewController.m +++ b/samples/JustRequestSample/JustRequestSample/JRViewController.m @@ -60,28 +60,28 @@ - (void)buttonRequestClickHandler:(id)sender { // login is integrated with the send button -- so if open, we send [self sendRequests]; } else { - [FBSession sessionOpenWithPermissions:nil - completionHandler: - ^(FBSession *session, - FBSessionState status, - NSError *error) { - // if login fails for any reason, we alert - if (error) { - UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Error" - message:error.localizedDescription - delegate:nil - cancelButtonTitle:@"OK" - otherButtonTitles:nil]; - [alert show]; - // if otherwise we check to see if the session is open, an alternative to - // to the FB_ISSESSIONOPENWITHSTATE helper-macro would be to check the isOpen - // property of the session object; the macros are useful, however, for more - // detailed state checking for FBSession objects - } else if (FB_ISSESSIONOPENWITHSTATE(status)) { - // send our requests if we successfully logged in - [self sendRequests]; - } - }]; + [FBSession openActiveSessionWithPermissions:nil + allowLoginUI:YES + completionHandler:^(FBSession *session, + FBSessionState status, + NSError *error) { + // if login fails for any reason, we alert + if (error) { + UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Error" + message:error.localizedDescription + delegate:nil + cancelButtonTitle:@"OK" + otherButtonTitles:nil]; + [alert show]; + // if otherwise we check to see if the session is open, an alternative to + // to the FB_ISSESSIONOPENWITHSTATE helper-macro would be to check the isOpen + // property of the session object; the macros are useful, however, for more + // detailed state checking for FBSession objects + } else if (FB_ISSESSIONOPENWITHSTATE(status)) { + // send our requests if we successfully logged in + [self sendRequests]; + } + }]; } } diff --git a/samples/PlacePickerSample/PlacePickerSample/PPViewController.m b/samples/PlacePickerSample/PlacePickerSample/PPViewController.m index 35e32e32c5..61b4c1bc27 100644 --- a/samples/PlacePickerSample/PlacePickerSample/PPViewController.m +++ b/samples/PlacePickerSample/PlacePickerSample/PPViewController.m @@ -55,22 +55,20 @@ - (void)refresh { [self searchDisplayController:nil shouldReloadTableForSearchScope:SampleLocationSeattle]; } else { // if the session isn't open, we open it here, which may cause UX to log in the user - [FBSession sessionOpenWithPermissions:nil - completionHandler: - ^(FBSession *session, FBSessionState status, NSError *error) - { - if (!error) { - [self refresh]; - } else { - [[[UIAlertView alloc] initWithTitle:@"Error" - message:error.localizedDescription - delegate:nil - cancelButtonTitle:@"OK" - otherButtonTitles:nil] - show]; - } - } - ]; + [FBSession openActiveSessionWithPermissions:nil + allowLoginUI:YES + completionHandler:^(FBSession *session, FBSessionState status, NSError *error) { + if (!error) { + [self refresh]; + } else { + [[[UIAlertView alloc] initWithTitle:@"Error" + message:error.localizedDescription + delegate:nil + cancelButtonTitle:@"OK" + otherButtonTitles:nil] + show]; + } + }]; } } diff --git a/samples/Scrumptious/scrumptious/SCAppDelegate.h b/samples/Scrumptious/scrumptious/SCAppDelegate.h index 8332f93882..7b4828ea59 100644 --- a/samples/Scrumptious/scrumptious/SCAppDelegate.h +++ b/samples/Scrumptious/scrumptious/SCAppDelegate.h @@ -33,6 +33,6 @@ extern NSString *const SCSessionStateChangedNotification; // The app delegate is responsible for maintaining the current FBSession. The application requires // the user to be logged in to Facebook in order to do anything interesting -- if there is no valid // FBSession, a login screen is displayed. -- (void)openSession; +- (BOOL)openSessionWithAllowLoginUI:(BOOL)allowLoginUI; @end diff --git a/samples/Scrumptious/scrumptious/SCAppDelegate.m b/samples/Scrumptious/scrumptious/SCAppDelegate.m index 854fc39ac0..1668207e90 100644 --- a/samples/Scrumptious/scrumptious/SCAppDelegate.m +++ b/samples/Scrumptious/scrumptious/SCAppDelegate.m @@ -106,12 +106,13 @@ - (void)sessionStateChanged:(FBSession *)session } } -- (void)openSession { +- (BOOL)openSessionWithAllowLoginUI:(BOOL)allowLoginUI { NSArray *permissions = [NSArray arrayWithObjects:@"publish_actions", @"user_photos", nil]; - [FBSession sessionOpenWithPermissions:permissions completionHandler: - ^(FBSession *session, FBSessionState state, NSError *error) { - [self sessionStateChanged:session state:state error:error]; - }]; + return [FBSession openActiveSessionWithPermissions:permissions + allowLoginUI:allowLoginUI + completionHandler:^(FBSession *session, FBSessionState state, NSError *error) { + [self sessionStateChanged:session state:state error:error]; + }]; } - (BOOL)application:(UIApplication *)application @@ -158,11 +159,8 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:( // FBSample logic // See if we have a valid token for the current state. - if (FBSession.activeSession.state == FBSessionStateCreatedTokenLoaded) { - // Yes, so just open the session (this won't display any UX). - [self openSession]; - } else { - // No, display the login page. + if (![self openSessionWithAllowLoginUI:NO]) { + // No? Display the login page. [self showLoginView]; } diff --git a/samples/Scrumptious/scrumptious/SCLoginViewController.m b/samples/Scrumptious/scrumptious/SCLoginViewController.m index a6f051a9f3..07eb2b617c 100644 --- a/samples/Scrumptious/scrumptious/SCLoginViewController.m +++ b/samples/Scrumptious/scrumptious/SCLoginViewController.m @@ -37,7 +37,7 @@ - (IBAction)performLogin:(id)sender { // FBSample logic // The user has initiated a login, so call the openSession method. SCAppDelegate *appDelegate = [UIApplication sharedApplication].delegate; - [appDelegate openSession]; + [appDelegate openSessionWithAllowLoginUI:YES]; } - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil { diff --git a/src/FBLoginView.m b/src/FBLoginView.m index 047c4d529a..291272527b 100644 --- a/src/FBLoginView.m +++ b/src/FBLoginView.m @@ -128,11 +128,11 @@ - (void)initialize { self.autoresizesSubviews = YES; self.clipsToBounds = YES; - // if our session has a cached token ready, we open it; note that - // it is important that we open it before wiring is in place to cause KVO, etc. - if (FBSession.activeSession.state == FBSessionStateCreatedTokenLoaded) { - [FBSession sessionOpenWithPermissions:self.permissions completionHandler:nil]; - } + // if our session has a cached token ready, we open it; note that it is important + // that we open the session before notification wiring is in place + [FBSession openActiveSessionWithPermissions:self.permissions + allowLoginUI:NO + completionHandler:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleActiveSessionSetNotifications:) @@ -285,11 +285,10 @@ - (void)wireViewForSessionWithoutOpening:(FBSession *)session { - (void)wireViewForSession:(FBSession *)session { [self wireViewForSessionWithoutOpening:session]; - // anytime we find that our session is created with an available token - // we open it on the spot - if (self.session.state == FBSessionStateCreatedTokenLoaded) { - [FBSession sessionOpenWithPermissions:self.permissions completionHandler:nil]; - } + // open the active session on the spot... + [FBSession openActiveSessionWithPermissions:self.permissions + allowLoginUI:NO // ... but only if a token is at the ready + completionHandler:nil]; } - (void)unwireViewForSession { @@ -335,7 +334,9 @@ - (void)actionSheet:(UIActionSheet *)actionSheet didDismissWithButtonIndex:(NSIn - (void)buttonPressed:(id)sender { if (self.session == FBSession.activeSession) { if (!self.session.isOpen) { // login - [FBSession sessionOpenWithPermissions:self.permissions completionHandler:nil]; + [FBSession openActiveSessionWithPermissions:self.permissions + allowLoginUI:YES + completionHandler:nil]; } else { // logout action sheet NSString *name = self.user.name; NSString *title = nil; diff --git a/src/FBSession.h b/src/FBSession.h index 50ef3d54ce..80b39b38a5 100644 --- a/src/FBSession.h +++ b/src/FBSession.h @@ -311,8 +311,25 @@ typedef void (^FBSessionReauthorizeResultHandler)(FBSession *session, This is the simplest method for opening a session with Facebook. Using sessionOpen logs on a user, and sets the static activeSession which becomes the default session object for any Facebook UI widgets used by the application. This session becomes the active session, whether open succeeds or fails. + + Note, if there is not a cached token available, this method will present UI to the user in order to + open the session via explicit login by the user. + + @param allowLoginUI Sometimes it is useful to attempt to open a session, but only if + no login UI will be required to accomplish the operation. For example, at application startup it may not + be disirable to transition to login UI for the user, and yet an open session is desired so long as a cached + token can be used to open the session. Passing NO to this argument, assures the method will not present UI + to the user in order to open the session. + + @discussion + Returns YES if the session was opened synchronously without presenting UI to the user. This occurs + when there is a cached token available from a previous run of the application. If NO is returned, this indicates + that the session was not immediately opened, via cache. However, if YES was passed as allowLoginUI, then it is + possible that the user will login, and the session will become open asynchronously. The primary use for + this return value is to switch-on facebook capabilities in your UX upon startup, in the case were the session + is opened via cache. */ -+ (FBSession*)sessionOpen; ++ (BOOL)openActiveSessionWithAllowLoginUI:(BOOL)allowLoginUI; /*! @abstract @@ -321,15 +338,30 @@ typedef void (^FBSessionReauthorizeResultHandler)(FBSession *session, used by the application. This session becomes the active session, whether open succeeds or fails. @param permissions An array of strings representing the permissions to request during the - authentication flow. A value of nil will indicates basic permissions. - A nil value specifies default permissions. + authentication flow. A value of nil will indicates basic permissions. A nil value specifies + default permissions. + + @param allowLoginUI Sometimes it is useful to attempt to open a session, but only if + no login UI will be required to accomplish the operation. For example, at application startup it may not + be desirable to transition to login UI for the user, and yet an open session is desired so long as a cached + token can be used to open the session. Passing NO to this argument, assures the method will not present UI + to the user in order to open the session. + + @param handler Many applications will benefit from notification when a session becomes invalid + or undergoes other state transitions. If a block is provided, the FBSession + object will call the block each time the session changes state. - @param handler Many applications will benefit from notification when a session becomes invalid - or undergoes other state transitions. If a block is provided, the FBSession - object will call the block each time the session changes state. + @discussion + Returns true if the session was opened synchronously without presenting UI to the user. This occurs + when there is a cached token available from a previous run of the application. If NO is returned, this indicates + that the session was not immediately opened, via cache. However, if YES was passed as allowLoginUI, then it is + possible that the user will login, and the session will become open asynchronously. The primary use for + this return value is to switch-on facebook capabilities in your UX upon startup, in the case were the session + is opened via cache. */ -+ (FBSession*)sessionOpenWithPermissions:(NSArray*)permissions - completionHandler:(FBSessionStateHandler)handler; ++ (BOOL)openActiveSessionWithPermissions:(NSArray*)permissions + allowLoginUI:(BOOL)allowLoginUI + completionHandler:(FBSessionStateHandler)handler; /*! @abstract diff --git a/src/FBSession.m b/src/FBSession.m index b7b7e5d766..41c5cb4e6c 100644 --- a/src/FBSession.m +++ b/src/FBSession.m @@ -444,25 +444,26 @@ - (void)setUrlSchemeSuffix:(NSString*)newValue { #pragma mark - #pragma mark Class Methods -/*! - @abstract - This is the simplest method for opening a session with Facebook. Using sessionOpen logs on a user, - and sets the static activeSession which becomes the default session object for any Facebook UI controls - used by the application. - */ -+ (FBSession*)sessionOpen { - return [FBSession sessionOpenWithPermissions:nil - completionHandler:nil]; ++ (BOOL)openActiveSessionWithAllowLoginUI:(BOOL)allowLoginUI { + return [FBSession openActiveSessionWithPermissions:nil + allowLoginUI:allowLoginUI + completionHandler:nil]; + } -+ (FBSession*)sessionOpenWithPermissions:(NSArray*)permissions ++ (BOOL)openActiveSessionWithPermissions:(NSArray*)permissions + allowLoginUI:(BOOL)allowLoginUI completionHandler:(FBSessionStateHandler)handler { + BOOL result = NO; FBSession *session = [[[FBSession alloc] initWithPermissions:permissions] autorelease]; - [FBSession setActiveSession:session]; - // we open after the fact, in order to avoid overlapping close - // and open handler calls for blocks - [session openWithCompletionHandler:handler]; - return session; + if (allowLoginUI || session.state == FBSessionStateCreatedTokenLoaded) { + [FBSession setActiveSession:session]; + // we open after the fact, in order to avoid overlapping close + // and open handler calls for blocks + [session openWithCompletionHandler:handler]; + result = session.isOpen; + } + return result; } + (FBSession*)activeSession { diff --git a/src/FBUserSettingsViewController.m b/src/FBUserSettingsViewController.m index 793c7244f1..1abc082723 100644 --- a/src/FBUserSettingsViewController.m +++ b/src/FBUserSettingsViewController.m @@ -296,10 +296,11 @@ - (void)openSession { self.attemptingLogin = YES; - [FBSession sessionOpenWithPermissions:self.permissions completionHandler: - ^(FBSession *session, FBSessionState state, NSError *error) { - [self sessionStateChanged:session state:state error:error]; - }]; + [FBSession openActiveSessionWithPermissions:self.permissions + allowLoginUI:YES + completionHandler:^(FBSession *session, FBSessionState state, NSError *error) { + [self sessionStateChanged:session state:state error:error]; + }]; } #pragma mark Handlers