Permalink
Browse files

[ios-sdk] Fix Scrumptious to handle session invalidation better; don'…

…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...
1 parent f268f1b commit 81c56ce413a0e06d0cd5a918b9300e3b32c29b32 @clang13 clang13 committed Sep 20, 2012
@@ -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;
@@ -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
@@ -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
@@ -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) {
@@ -156,7 +159,8 @@ - (void)postAction:(NSString *)actionPath
[self postAction:actionPath
leftOperand:left
rightOperand:right
- result:result];
+ result:result
+ tryReauthIfNeeded:NO];
}
}];
} else {
@@ -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];
+ }
}
}];
}
@@ -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";
@@ -25,6 +25,7 @@ @interface SCAppDelegate ()
@property (strong, nonatomic) UINavigationController *navController;
@property (strong, nonatomic) SCViewController *mainViewController;
+@property (strong, nonatomic) SCLoginViewController* loginViewController;
- (void)showLoginView;
@@ -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];
}
}
@@ -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.
@@ -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;
View
@@ -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 {
@@ -1567,6 +1571,9 @@ + (NSString *)sessionStateDescription:(FBSessionState)sessionState {
case FBSessionStateCreatedTokenLoaded:
stateDescription = @"FBSessionStateCreatedTokenLoaded";
break;
+ case FBSessionStateCreatedOpening:
+ stateDescription = @"FBSessionStateCreatedOpening";
+ break;
case FBSessionStateOpen:
stateDescription = @"FBSessionStateOpen";
break;

0 comments on commit 81c56ce

Please sign in to comment.