Skip to content

Commit

Permalink
[ios-sdk] Fix Scrumptious to handle session invalidation better; don'…
Browse files Browse the repository at this point in the history
…t try to re-close FBSession if it is already closed.

Summary:
Depending on when Scrumptious encountered an invalid session state change, it was not always correctly
presenting its login view.

[FBSession closeAndClearTokenInformation] should not transition state if the session is already closed.

Test Plan:
- Ran Scrumptious on iOS6 simulator and device

Revert Plan:

Reviewers: jacl

Reviewed By: jacl

CC: msdkexp@

Differential Revision: https://phabricator.fb.com/D580143
  • Loading branch information
Chris Lang committed Sep 21, 2012
1 parent f268f1b commit 81c56ce
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 46 deletions.
63 changes: 44 additions & 19 deletions samples/BooleanOGSample/BooleanOGSample/BOGFirstViewController.m
Expand Up @@ -24,7 +24,8 @@ @interface BOGFirstViewController () <UIPickerViewDelegate>
- (void)postAction:(NSString *)actionPath
leftOperand:(BOOL)left
rightOperand:(BOOL)right
result:(BOOL)result;
result:(BOOL)result
tryReauthIfNeeded:(BOOL)tryReauthIfNeeded;
- (NSString *)stringForTruthValue:(BOOL)truthValue;
+ (id<BOGGraphTruthValue>)ogObjectForTruthValue:(BOOL)value;

Expand Down Expand Up @@ -83,7 +84,8 @@ - (IBAction)pressedAnd:(id)sender {
[self postAction:@"me/fb_sample_boolean_og:and"
leftOperand:left
rightOperand:right
result:result];
result:result
tryReauthIfNeeded:YES];
}

// FBSample logic
Expand All @@ -103,7 +105,8 @@ - (IBAction)pressedOr:(id)sender {
[self postAction:@"me/fb_sample_boolean_og:or"
leftOperand:left
rightOperand:right
result:result];
result:result
tryReauthIfNeeded:YES];
}

#pragma mark - UIPickerViewDelegate impl
Expand Down Expand Up @@ -140,14 +143,14 @@ - (void)pickerView:(UIPickerView *)pickerView
- (void)postAction:(NSString *)actionPath
leftOperand:(BOOL)left
rightOperand:(BOOL)right
result:(BOOL)result {
result:(BOOL)result
tryReauthIfNeeded:(BOOL)tryReauthIfNeeded {

// if we have a valid session, then we post the action to the users wall, else noop
if (FBSession.activeSession.isOpen) {

// if we don't have permission to post, let's first address that
if ([FBSession.activeSession.permissions indexOfObject:@"publish_actions"] == NSNotFound) {

[FBSession.activeSession reauthorizeWithPublishPermissions:[NSArray arrayWithObject:@"publish_actions"]
defaultAudience:FBSessionDefaultAudienceFriends
completionHandler:^(FBSession *session, NSError *error) {
Expand All @@ -156,7 +159,8 @@ - (void)postAction:(NSString *)actionPath
[self postAction:actionPath
leftOperand:left
rightOperand:right
result:result];
result:result
tryReauthIfNeeded:NO];
}
}];
} else {
Expand All @@ -176,33 +180,54 @@ - (void)postAction:(NSString *)actionPath
// post the action using one of the lightweight static start* methods on FBRequest
[FBRequestConnection startForPostWithGraphPath:actionPath
graphObject:action
completionHandler:^(FBRequestConnection *connection, id result, NSError *error) {
completionHandler:^(FBRequestConnection *connection, id requestResult, NSError *error) {
if (!error) {
// successful post, in the sample we do nothing with the id, however
// a more complex applicaiton may want to store or perform addtional actions
// a more complex application may want to store or perform addtional actions
// with the id that represents the just-posted action
} else {
// get the basic error message
NSString *message = error.localizedDescription;

// see if we can improve on it with an error message from the server
id json = [error.userInfo objectForKey:FBErrorParsedJSONResponseKey];
id facebookError = nil;
NSDecimalNumber *code = nil;
if ([json isKindOfClass:[NSDictionary class]] &&
(json = [json objectForKey:@"body"]) &&
[json isKindOfClass:[NSDictionary class]] &&
(json = [json objectForKey:@"error"]) &&
[json isKindOfClass:[NSDictionary class]] &&
(json = [json objectForKey:@"message"])) {
(facebookError = [json objectForKey:@"error"]) &&
[facebookError isKindOfClass:[NSDictionary class]] &&
(json = [facebookError objectForKey:@"message"])) {
message = [json description];
code = [facebookError objectForKey:@"code"];
}

// display the message that we have
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"OG Post Failed"
message:message
delegate:nil
cancelButtonTitle:@"OK"
otherButtonTitles:nil];
[alert show];
if ([code intValue] == 200 && tryReauthIfNeeded) {
// We got an error indicating a permission is missing. This could happen if the user has gone into
// their Facebook settings and explictly removed a permission they had previously granted. Try reauthorizing
// again to get the permission back.
[FBSession.activeSession reauthorizeWithPermissions:[NSArray arrayWithObject:@"publish_actions"]
behavior:FBSessionLoginBehaviorWithFallbackToWebView
completionHandler:^(FBSession *session, NSError *error) {
if (!error) {
// re-call assuming we now have the permission
[self postAction:actionPath
leftOperand:left
rightOperand:right
result:result
tryReauthIfNeeded:NO];
}
}];
} else {
// display the message that we have
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"OG Post Failed"
message:message
delegate:nil
cancelButtonTitle:@"OK"
otherButtonTitles:nil];
[alert show];
}
}
}];
}
Expand All @@ -221,7 +246,7 @@ - (NSString*)stringForTruthValue:(BOOL)truthValue {

// NOTE! Production applications must host OG objects using a server provisioned for use by the app
// These OG object URLs were created using the edit open graph feature of the graph tool
// at https://www.developers.facebook.com/apps/
// at https://developers.facebook.com/apps/
NSString *trueURL = @"http://samples.ogp.me/369360019783304";
NSString *falseURL = @"http://samples.ogp.me/369360256449947";

Expand Down
53 changes: 31 additions & 22 deletions samples/Scrumptious/scrumptious/SCAppDelegate.m
Expand Up @@ -25,6 +25,7 @@ @interface SCAppDelegate ()

@property (strong, nonatomic) UINavigationController *navController;
@property (strong, nonatomic) SCViewController *mainViewController;
@property (strong, nonatomic) SCLoginViewController* loginViewController;

- (void)showLoginView;

Expand All @@ -35,25 +36,25 @@ @implementation SCAppDelegate
@synthesize window = _window;
@synthesize mainViewController = _mainViewController;
@synthesize navController = _navController;
@synthesize loginViewController = _loginViewController;

#pragma mark -
#pragma mark Facebook Login Code

- (void)createAndPresentLoginView {
if (self.loginViewController == nil) {
self.loginViewController = [[SCLoginViewController alloc] initWithNibName:@"SCLoginViewController"
bundle:nil];
UIViewController *topViewController = [self.navController topViewController];
[topViewController presentModalViewController:self.loginViewController animated:NO];
}
}

- (void)showLoginView {
UIViewController *topViewController = [self.navController topViewController];
UIViewController *modalViewController = [topViewController modalViewController];

// FBSample logic
// If the login screen is not already displayed, display it. If the login screen is displayed, then
// getting back here means the login in progress did not successfully complete. In that case,
// notify the login view so it can update its UI appropriately.
if (![modalViewController isKindOfClass:[SCLoginViewController class]]) {
SCLoginViewController* loginViewController = [[SCLoginViewController alloc]initWithNibName:@"SCLoginViewController"
bundle:nil];
[topViewController presentModalViewController:loginViewController animated:NO];
if (self.loginViewController == nil) {
[self performSelector:@selector(createAndPresentLoginView) withObject:nil afterDelay:0.5f];
} else {
SCLoginViewController* loginViewController = (SCLoginViewController*)modalViewController;
[loginViewController loginFailed];
[self.loginViewController loginFailed];
}
}

Expand All @@ -67,11 +68,12 @@ - (void)sessionStateChanged:(FBSession *)session
// is opened successfully, hide the login controller and show the main UI.
switch (state) {
case FBSessionStateOpen: {
UIViewController *topViewController = [self.navController topViewController];
if ([[topViewController modalViewController] isKindOfClass:[SCLoginViewController class]]) {
if (self.loginViewController != nil) {
UIViewController *topViewController = [self.navController topViewController];
[topViewController dismissModalViewControllerAnimated:YES];
self.loginViewController = nil;
}

// FBSample logic
// Pre-fetch and cache the friends for the friend picker as soon as possible to improve
// responsiveness when the user tags their friends.
Expand All @@ -80,14 +82,21 @@ - (void)sessionStateChanged:(FBSession *)session
}
break;
case FBSessionStateClosed:
case FBSessionStateClosedLoginFailed:
// FBSample logic
// Once the user has logged out, we want them to be looking at the root view.
[self.navController popToRootViewControllerAnimated:NO];
case FBSessionStateClosedLoginFailed: {
// FBSample logic
// Once the user has logged out, we want them to be looking at the root view.
UIViewController *topViewController = [self.navController topViewController];
UIViewController *modalViewController = [topViewController modalViewController];
while (modalViewController != nil) {
[topViewController dismissModalViewControllerAnimated:NO];
modalViewController = [topViewController modalViewController];
}
[self.navController popToRootViewControllerAnimated:NO];

[FBSession.activeSession closeAndClearTokenInformation];
[FBSession.activeSession closeAndClearTokenInformation];

[self showLoginView];
[self showLoginView];
}
break;
default:
break;
Expand Down
17 changes: 12 additions & 5 deletions src/FBSession.m
Expand Up @@ -408,11 +408,15 @@ - (void)closeAndClearTokenInformation {

[[FBDataDiskCache sharedCache] removeDataForSession:self];
[self.tokenCachingStrategy clearToken];
[self transitionAndCallHandlerWithState:FBSessionStateClosed
error:nil
token:nil
expirationDate:nil
shouldCache:NO];

// If we are not already in a terminal state, go to Closed.
if (!FB_ISSESSIONSTATETERMINAL(self.state)) {
[self transitionAndCallHandlerWithState:FBSessionStateClosed
error:nil
token:nil
expirationDate:nil
shouldCache:NO];
}
}

- (BOOL)handleOpenURL:(NSURL *)url {
Expand Down Expand Up @@ -1567,6 +1571,9 @@ + (NSString *)sessionStateDescription:(FBSessionState)sessionState {
case FBSessionStateCreatedTokenLoaded:
stateDescription = @"FBSessionStateCreatedTokenLoaded";
break;
case FBSessionStateCreatedOpening:
stateDescription = @"FBSessionStateCreatedOpening";
break;
case FBSessionStateOpen:
stateDescription = @"FBSessionStateOpen";
break;
Expand Down

0 comments on commit 81c56ce

Please sign in to comment.