I want to put some Facebook integration in my app. At this point I've managed to login, post to friends wall, retrieve the list of friends, etc. Everything is OK except for one thing...
If the user removes the app from your Facebook settings / Applications and then enters to the iOS app, the code doesn't recognize that the Facebook app was removed from the user settings and assumes that is logged in (this is the problem because if the user tries to post to a friend's wall, the app do nothing).
Then, the user closes the iOS app and relaunches it... With this relaunch, the iOS app "is fixed" and detects that the user is no longer logged in.
I can't manage to detect the moment right after the user deletes the facebook app from the settings in order to bring the login flow to the user...
Here is my code:
At first scene of my app...
if([FBSession activeSession].state == FBSessionStateCreatedTokenLoaded)
{
NSLog(@"Logged in to Facebook");
[self openFacebookSession];
UIAlertView *alertDialog;
alertDialog = [[UIAlertView alloc] initWithTitle:@"Facebook" message:@"You're already logged in to Facebook" delegate:nil cancelButtonTitle:@"Ok" otherButtonTitles:nil, nil];
[alertDialog show];
[alertDialog release];
return YES;
}
else{
NSLog(@"Not logged in to Facebook"); //Show the login flow
return NO;
}
Here is the code for openFacebookSession
-(void)openFacebookSession
{
NSArray *permissions = [[NSArray alloc] initWithObjects:
@"publish_stream",
nil];
[FBSession openActiveSessionWithPublishPermissions:permissions defaultAudience:FBSessionDefaultAudienceFriends allowLoginUI:YES completionHandler:^(FBSession *session, FBSessionState status, NSError *error) {
[self sessionStateChanged:session state:status error:error];
}];
}
Code for sessionStateChanged...
-(void)sessionStateChanged:(FBSession *)session state:(FBSessionState)state error:(NSError *)error
{
switch (state) {
case FBSessionStateOpen: {
NSLog(@"Session opened");
}
break;
case FBSessionStateClosed:
case FBSessionStateClosedLoginFailed:
[FBSession.activeSession closeAndClearTokenInformation];
break;
default:
break;
}
if (error) {
UIAlertView *alertView = [[UIAlertView alloc]
initWithTitle:@"Error"
message:error.localizedDescription
delegate:nil
cancelButtonTitle:@"OK"
otherButtonTitles:nil];
[alertView show];
}
}
Thank you very much!
I found this happening to myself as well.... It was discovered when a user changed their facebook password, and we could no longer authenticate. Doing a manual resync / clear of the account session allowed them to login again.
-(void)syncFacebookAccount
{
[self forceLogout];
ACAccountStore *accountStore = [[ACAccountStore alloc] init];
ACAccountType *accountTypeFB = [accountStore accountTypeWithAccountTypeIdentifier:@"com.apple.facebook"];
if (accountStore && accountTypeFB) {
NSArray *fbAccounts = [accountStore accountsWithAccountType:accountTypeFB];
id account;
if (fbAccounts && [fbAccounts count] > 0 && (account = [fbAccounts objectAtIndex:0])) {
[accountStore renewCredentialsForAccount:account completion:^(ACAccountCredentialRenewResult renewResult, NSError *error) {
// Not actually using the completion handler...
}];
}
}
}
It's actually VERY hard to parse out and detect these types of errors for two reasons:
NSError
object passed from the failed FBRequest
is ABSURDLY difficult to parse and use in any functional way. Below is the crazy method I wrote while literally pulling an all-nighter to deal with this. It handles the NSError *error
object from the failed FBRequest
attempt, and passes it to the relevant methods OR displays the most sensible error I could find (or hits the bottom catch-all).
Note the comments - particularly around innerError
and parsedResponse
- that detail what I've discovered so far. Good luck, brave soldier:
- (void)handleFacebookError:(NSError *)error
withPermissionType:(RMFacebookPermissionsType)type // this is just a typedef enum specifying Write or Read permissions so I can react accordingly
withCompletion:(void (^)(BOOL retry))completionBlock {
newMethodDebugLog;
NSParameterAssert(error);
NSParameterAssert(type);
NSParameterAssert(completionBlock); // the completion block tells the controller whether the error is 'fatal' or can be recovered - if YES, it can be recovered
// this is the parsed result of the graph call; some errors can appear here, too, sadly
NSDictionary *parsedResponse = [error.userInfo objectForKey:@"com.facebook.sdk:ParsedJSONResponseKey"];
int parsedErrorCode = [[[[parsedResponse objectForKey:@"body"]
objectForKey:@"error"]
objectForKey:@"code"]
intValue];
// this is an instance of NSError created by Facebook; it contains details about the error
NSError *innerError = [error.userInfo objectForKey:@"com.facebook.sdk:ErrorInnerErrorKey"];
// innerError is usually un-recoverable
if (innerError) {
// innerError seems to be the response given in true HTTP problems;
DebugLog(@"______innerError FOUND______");
DebugLog(@"innerError: %@",innerError);
DebugLog(@"innerError.code: %d",innerError.code);
// digging deep enough, you can actually find a coherent error message! :D
DebugLog(@"innerError.localizedDescription: %@",innerError.localizedDescription);
if (![alert isVisible]) {
NSString *errorString = @"Facebook Connection Failed";
NSString *okString = @"OK";
alert = [[UIAlertView alloc] initWithTitle:errorString
message:innerError.localizedDescription
delegate:nil
cancelButtonTitle:okString
otherButtonTitles:nil];
[alert show];
} else {
DebugLog(@"Alert already showing!");
}
completionBlock(NO);
} else if (parsedResponse &&
parsedErrorCode != 2) { // I honestly forget what error 2 is.. documentation fail :(
// parsedResponses can usually be recovered
DebugLog(@"parsed response values: %@",[parsedResponse allValues]);
switch (parsedErrorCode) {
case 2500:
case 200:
case 190:
{
DebugLog(@"parsedError code hit! forcing re-login.");
// all errors in case 190 seem to be OAuth issues
// http://fbdevwiki.com/wiki/Error_codes#Parameter_Errors
// if needed, "error_subcode" 458 == user has de-authorized your app
// case 2500 reported while grabbing from a photo album & not logged in
// case 200 "requires extended permission: publish_actions"
if (type == RMFacebookPermissionsTypeRead) {
[self _getFacebookReadPermissionsWithUI:YES
completion:completionBlock];
} else if (type == RMFacebookPermissionsTypeWrite) {
[self _getFacebookWritePermissionsWithUI:YES
completion:completionBlock];
}
break;
}
default:
completionBlock(YES);
break;
}
} else {
if (![alert isVisible]) {
NSString *errorString = @"Facebook Error";
NSString *messageString = @"Mixture Photos was unable to connect to Facebook on your behalf. This is usually a temporary problem. Please try again later.";
NSString *okString = @"OK";
alert = [[UIAlertView alloc] initWithTitle:errorString
message:messageString
delegate:nil
cancelButtonTitle:okString
otherButtonTitles:nil];
[alert show];
} else {
DebugLog(@"Alert already showing!");
}
completionBlock(NO);
}
}
I have the same problem and could not find proper documentation about error codes on Facebook SDK site.
I solved problem by comparing the [error code];
or [error userInfo];
value.
Your session will have the state FBSessionStateClosedLoginFailed
and userInfo dictionary of error will have the following form
"com.facebook.sdk:ErrorLoginFailedReason" = "com.facebook.sdk:ErrorLoginFailedReason";
On the other hand error code shows me 2
so that you can handle it at the end of sessionStateChanged::: function
- (void)sessionStateChanged:(FBSession *)session
state:(FBSessionState)state
error:(NSError *)error {
switch (state) {
case FBSessionStateOpen: {
//update permissionsArrat
[self retrieveUSerPermissions];
if (!needstoReopenOldSession) {
//First User information
[self getUserInformation:nil];
}
NSNotification *authorizationNotification = [NSNotification notificationWithName:facebookAuthorizationNotification object:nil];
[[NSNotificationCenter defaultCenter] postNotification:authorizationNotification];
}
case FBSessionStateClosed: {
break;
}
case FBSessionStateClosedLoginFailed: {
[FBSession.activeSession closeAndClearTokenInformation];
break;
}
default:
break;
}
if (error)
{
NSNotification *authorizationNotification = [NSNotification notificationWithName:faceBookErrorOccuredNotification object:error];
[[NSNotificationCenter defaultCenter] postNotification:authorizationNotification];
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.