Always return Error FBErrorCategoryUserCancelled while login with facebook in my application - facebook

In my Application there are three ways of login. one of them is login with facebook. But when I click on facebook button it ask me for accesing permissions, when click OK then it returs error FBErrorCategoryUserCancelled. And this is not happening on every devices, it happens on some devices. Here is my code -
if ([[FBSession activeSession]isOpen]) {
/*
* if the current session has no publish permission we need to reauthorize
*/
if ([[[FBSession activeSession]permissions]indexOfObject:#"publish_actions"] == NSNotFound) {
[[FBSession activeSession] requestNewPublishPermissions:[NSArray arrayWithObject:#"publish_actions"] defaultAudience:FBSessionDefaultAudienceFriends
completionHandler:^(FBSession *session,NSError *error){
[ProgressHUD dismiss];
self.view.userInteractionEnabled = YES;
}];
}else{
[self fetchUserDetails];
}
}else{
/*
* open a new session with publish permission
*/
[FBSession openActiveSessionWithPublishPermissions:[NSArray arrayWithObject:#"publish_actions"]
defaultAudience:FBSessionDefaultAudienceOnlyMe
allowLoginUI:YES
completionHandler:^(FBSession *session, FBSessionState status, NSError *error) {
if (!error && status == FBSessionStateOpen) {
[self fetchUserDetails];
}else{
NSLog(#"error");
if ([FBErrorUtility shouldNotifyUserForError:error]) {
alertTitle = #"Facebook Error";
alertMessage = [FBErrorUtility userMessageForError:error];
// This code will handle session closures that happen outside of the app
// You can take a look at our error handling guide to know more about it
// https://developers.facebook.com/docs/ios/errors
} else if ([FBErrorUtility errorCategoryForError:error] == FBErrorCategoryAuthenticationReopenSession) {
alertTitle = #"Session Error";
alertMessage = #"Your current session is no longer valid. Please log in again.";
// If the user has cancelled a login, we will do nothing.
// You can also choose to show the user a message if cancelling login will result in
// the user not being able to complete a task they had initiated in your app
// (like accessing FB-stored information or posting to Facebook)
} else if ([FBErrorUtility errorCategoryForError:error] == FBErrorCategoryUserCancelled) {
NSLog(#"user cancelled login");
alertTitle = #"Facebook Error";
alertMessage = #"System login cancelled";
// For simplicity, this sample handles other errors with a generic message
// You can checkout our error handling guide for more detailed information
// https://developers.facebook.com/docs/ios/errors
} else {
alertTitle = #"Something went wrong";
alertMessage = #"Please try again later.";
NSLog(#"Unexpected error:%#", error);
}
[[[UIAlertView alloc] initWithTitle:alertTitle
message:alertMessage
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil] show];
[ProgressHUD dismiss];
self.view.userInteractionEnabled = YES;
}
}];
}
Any help will be appreciated.Thank you.

In my case it was because the facebook app's sandbox mode was still on, and therefore result in FBErrorCategoryUserCancelled for anyone who is not an administrator/developer/tester of the app.
To turn off sandbox mode on facebook, go to
https://developers.facebook.com/apps/YOUR_FACEBOOK_APP_ID/review-status/
See where it says "Do you want to make this app and all its live features available to the general public?", make it to be YES. (You might need to insert a contact email before you can access this option).
Or, if you don't want to make the app go public just yet, invite the tester to be an admin/developer/tester of the app. The person need to accept your invitation before he can use it.

Related

Parse Anypic Facebook login error

I am exprimenting with Parse's Anypic and I keep getting these 3 errors:
Presenting view controllers on detached view controllers is discouraged <PAPWelcomeViewController>
then goes
Unbalanced calls to begin/end appearance transitions for <UINavigationController>
and finally
Login failure. FB Access Token or user ID does not exist
I'm setting everything up just as it was stated in the tutorial. It was working fine in the past and I wasn't getting these errors, however when I came back to the project after some time I am getting these.
They are happening while trying to log in to the app through Facebook. I select login, put my details, click login and then nothing happens, it just goes back to the "log in with facebook" button.
Thanks for help!
You should try to change handleFacebookSession to look like this:
- (void)handleFacebookSession {
if ([PFUser currentUser]) {
if (self.delegate && [self.delegate respondsToSelector:#selector(logInViewControllerDidLogUserIn:)]) {
[self.delegate performSelector:#selector(logInViewControllerDidLogUserIn:) withObject:[PFUser currentUser]];
}
return;
}
NSArray *permissionsArray = #[ #"public_profile",
#"user_friends",
#"email"];
self.hud = [MBProgressHUD showHUDAddedTo:self.view animated:YES];
// Login PFUser using Facebook
[PFFacebookUtils logInWithPermissions:permissionsArray block:^(PFUser *user, NSError *error) {
if (!user) {
NSString *errorMessage = nil;
if (!error) {
NSLog(#"Uh oh. The user cancelled the Facebook login.");
errorMessage = #"Uh oh. The user cancelled the Facebook login.";
} else {
NSLog(#"Uh oh. An error occurred: %#", error);
errorMessage = [error localizedDescription];
}
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Log In Error"
message:errorMessage
delegate:nil
cancelButtonTitle:nil
otherButtonTitles:#"Dismiss", nil];
[alert show];
} else {
if (user.isNew) {
NSLog(#"User with facebook signed up and logged in!");
} else {
NSLog(#"User with facebook logged in!");
}
if (!error) {
[self.hud removeFromSuperview];
if (self.delegate) {
if ([self.delegate respondsToSelector:#selector(logInViewControllerDidLogUserIn:)]) {
[self.delegate performSelector:#selector(logInViewControllerDidLogUserIn:) withObject:user];
}
}
} else {
[self cancelLogIn:error];
}
}
}];}
Solution was taken from here

Facebook login in iOS app for multiple users on one device

My app will be used by multiple users.
How can I integrate facebook in a way so that the safari doesn't save any user credentials & throw a login page each time some one tries to login.
I already used FBSessionLoginBehaviorForcingWebView to force a web view login within the app but the problem is, when the first user tries to login to fb via the view presented within the app, the control then goes to safari for authentication & it just saves the creds.
So when other user tries to log in, & enters his credentials in the app local UIWebView, the control again goes to safari, which already has previos creds stored & the new user just cannot authenticate.
So basically the first user is permanently logged in. Clearing the cookies for web view doesn't work. I cant clear them for safari.
Help
Thanks in advance.
This is what I have been doing
if([FBSession activeSession].isOpen)
{
[[FBSession activeSession] closeAndClearTokenInformation];//Also, clearing all the local cookies
}
else
{
AppDelegate *delegate = [UIApplication sharedApplication].delegate;
delegate.session = [[FBSession alloc] init];
[FBSession setActiveSession:delegate.session];
[delegate.session openWithBehavior:FBSessionLoginBehaviorForcingWebView completionHandler:^(FBSession *session1, FBSessionState status, NSError *error) {
if (!error) {
[self openSession]; // your method
}
}];
}
- (void)sessionStateChanged:(FBSession *)session state:(FBSessionState) state error:(NSError *)error{
switch (state) {
case FBSessionStateOpen:
{
[FBRequestConnection startForPostStatusUpdate:#"Some message"completionHandler:^(FBRequestConnection *connection, id result, NSError *error) {
if (!error) {
//logout again
NSLog(#"startForPostStatusUpdate SUCESS");
}
else {
//logout again
NSLog(#"startForPostStatusUpdate FAIL");
}
}];
}
break;
case FBSessionStateClosed:
{
NSLog(#"FBSessionStateClosed");
}
break;
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];
}
}
Also, modified the app delegate with your methods.
Found a solution. Basically, calling the following:
[FBSession.activeSession closeAndClearTokenInformation];
[FBSession.activeSession close];
[FBSession setActiveSession:nil];
Only clears the local FB session information but not the Safari cookies. So, after I log in the user, I clear the Safari cookies:
NSHTTPCookie *cookie;
NSHTTPCookieStorage *storage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
for (cookie in [storage cookies]) {
[storage deleteCookie:cookie];
}
[[NSUserDefaults standardUserDefaults] synchronize];
It isn't very elegant, but it works. Now, when the next user tries to log in, it forces them to enter their credentials.
You just need to use this method after you want to close the FB Session.
[FBSession.activeSession closeAndClearTokenInformation];
This will clear the Facebook Token, and whenever button will be pressed for Facebook share, it will ask for new token credential and it will show Facebook login view again.
Use following code in AppDelegate
// This method will handle facebook session.
- (BOOL)application:(UIApplication *)application
openURL:(NSURL *)url
sourceApplication:(NSString *)sourceApplication
annotation:(id)annotation
{
// Facebook SDK * login flow *
// Attempt to handle URLs to complete any auth (e.g., SSO) flow.
return [FBAppCall handleOpenURL:url sourceApplication:sourceApplication fallbackHandler:^(FBAppCall *call) {
// Facebook SDK * App Linking *
// For simplicity, this sample will ignore the link if the session is already
// open but a more advanced app could support features like user switching.
if (call.accessTokenData) {
if ([FBSession activeSession].isOpen) {
NSLog(#"INFO: Ignoring app link because current session is open.");
}
else {
[self handleAppLink:call.accessTokenData];
}
}
}];
}
// Helper method to wrap logic for handling app links.
- (void)handleAppLink:(FBAccessTokenData *)appLinkToken {
// Initialize a new blank session instance...
FBSession *appLinkSession = [[FBSession alloc] initWithAppID:nil
permissions:nil
defaultAudience:FBSessionDefaultAudienceNone
urlSchemeSuffix:nil
tokenCacheStrategy:[FBSessionTokenCachingStrategy nullCacheInstance] ];
[FBSession setActiveSession:appLinkSession];
// ... and open it from the App Link's Token.
[appLinkSession openFromAccessTokenData:appLinkToken
completionHandler:^(FBSession *session, FBSessionState status, NSError *error) {
// Forward any errors to the FBLoginView delegate.
if (error) {
//TODO: Show error here
}
}];
}
Add following code where you are opening session for Facebook
/***********************************************************************
This method opens browser or App Url to FB authentication and change FB
session state
************************************************************************/
- (void)openSession
{
NSArray *permisssions = [[NSArray alloc] initWithObjects:#"email",#"user_photos",nil];
[FBSession openActiveSessionWithReadPermissions:permisssions
allowLoginUI:YES
completionHandler:
^(FBSession *session,
FBSessionState state, NSError *error) {
[self sessionStateChanged:session state:state error:error];
}];
}
/***********************************************************************
This method will be called whenever FB Session state changed
It also shows an error message if any error occurs
************************************************************************/
- (void)sessionStateChanged:(FBSession *)session
state:(FBSessionState) state
error:(NSError *)error
{
switch (state) {
case FBSessionStateOpen: {
NSLog(#"FBSession Open State");
//Enter your code what you want to perform when session is open
}
break;
case FBSessionStateClosed:
case FBSessionStateClosedLoginFailed:
// Once the user has logged in, we want them to
// be looking at the root view.
NSLog(#"FBSession State Closed");
[FBSession.activeSession closeAndClearTokenInformation];
[FBSession.activeSession close];
[FBSession setActiveSession:nil];
break;
default:
break;
}
if (error) {
UIAlertView *alertView = [[UIAlertView alloc]
initWithTitle:#"Error"
message:error.localizedDescription
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alertView show];
}
}
Now when ever user tap on Facebook Share button check that session exists or not. If not then call openSession method. It will open facebook login view.
There is a sample in the Facebook Github repository, showing how to switch between multiple users.
It looks like it requires use of the custom login flow.

Fb request dialog returns nil incorrectly - IOS Facebook

Thanks for reading!
I'm trying to create a Facebook request to enable the user to invite his friends to the app.
NSDictionary *params = [[NSDictionary alloc] initWithObjectsAndKeys:nil];
[FBWebDialogs
presentRequestsDialogModallyWithSession:nil
message:#"Learn how to make your iOS apps social."
title:#"Test"
parameters:params
handler:^(FBWebDialogResult result, NSURL *resultURL, NSError *error) {
if (error) {
// Error launching the dialog or sending the request.
NSLog(#"Error sending request.");
} else {
if (result == FBWebDialogResultDialogNotCompleted) {
// User clicked the "x" icon
NSLog(#"User canceled request.");
} else {
// Handle the send request callback
NSDictionary *urlParams = [self parseURLParams:[resultURL query]];
if (![urlParams valueForKey:#"request"]) {
// User clicked the Cancel button
NSLog(#"User canceled request.");
} else {
// User clicked the Send button
NSString *requestID = [urlParams valueForKey:#"request"];
NSLog(#"Request ID: %#", requestID);
}
}
}
}];
}
This is pretty much a clean copy of the Facebook docs code. And it works up to a point
The user can choose the friends and the request goes away and gets received by the friends and it shows up as a notification - everything fine so far.
The problem is that when I try to get the response from the "handler" the resultURL is nil and does not contain anything. And after that I get the log message "User canceled request".
Why don't I get anything back? The main reason that I need this is that I need to know which friends the request was sent to.
Thank you for any help!
Seems like you're passing an nil empty session to presentRequestsDialogModallyWithSession
Use FBSession.activeSession instead and check you have enough permissions to run the request (although if not, you would be getting another different error)
I think you are not having a session opened..please try to use this to open the session.
if (!FBSession.activeSession.isOpen) {
// if the session is closed, then we open it here, and establish a handler for state changes
[FBSession openActiveSessionWithReadPermissions:nil
allowLoginUI:YES
completionHandler:^(FBSession *session,
FBSessionState state,
NSError *error) {
}];
}

Facebook SDK 3.1 error when posting from iOS app

I'm facing the following problems with my iOS app:
While publishing to user's friend's wall, using iOS app I'm getting the error "com.facebook.sdk error 5".
The app is asking to login every time when I check for "FBSession.activeSession.isOpen".
Everything was working fine before. But since I've changed my app ID (as now I have to use different Facebook app). I'm getting the error.
I've done some research on this and found some solutions. Ive tried them all but nothing works.
I've written the following code to login to Facebook:
- (BOOL)openSessionWithAllowLoginUI:(BOOL)allowLoginUI {
comingfromFB = YES;
NSArray *permissions = [[NSArray alloc] initWithObjects:
#"friends_birthday",
nil];
return [FBSession openActiveSessionWithReadPermissions:permissions
allowLoginUI:allowLoginUI
completionHandler:^(FBSession *session, FBSessionState state, NSError *error) {
[self sessionStateChanged:session state:state error:error];
}];
}
And the following code for publishing story:
if ([FBSession.activeSession.permissions
indexOfObject:#"publish_actions"] == NSNotFound) {
// No permissions found in session, ask for it
[FBSession.activeSession
reauthorizeWithPublishPermissions:
[NSArray arrayWithObject:#"publish_actions"]
defaultAudience:FBSessionDefaultAudienceFriends
completionHandler:^(FBSession *session, NSError *error) {
if (!error) {
// If permissions granted, publish the story
[self publishStory];
}
}];
} else {
// If permissions present, publish the story
[self publishStory];
}
When I run the app I get the following error:
Error: HTTP status code: 403
2013-02-05 14:36:47.109 <appname>[1705:c07] Error Domain=com.facebook.sdk Code=5 "The operation couldn’t be completed. (com.facebook.sdk error 5.)" UserInfo=0xaa9af20 {com.facebook.sdk:ParsedJSONResponseKey={
body = {
error = {
code = 200;
message = "(#200) The user hasn't authorized the application to perform this action";
type = OAuthException;
};
};
code = 403;
}, com.facebook.sdk:HTTPStatusCode=403}
Please help me to understand where I'm going wrong.
I've also added some key-value pair to NSUserDefaults. Could that be a possible reason for that?
Thanks.
When you're first showing your view with post button, perhaps you want to check if the session is open and set your post button title according to session state. Assuming your button initially has "Post" title:
[FBSession openActiveSessionWithAllowLoginUI: NO];
if (![FBSession.activeSession isOpen])
{
[self setSendButtonTitle:NSLocalizedString(#"Log in",#"")];
}
Then add the following code to your Post button action:
- (void) send: (UIButton*) sender
{
if (![FBSession.activeSession isOpen])
{
[FBSession openActiveSessionWithPublishPermissions: [NSArray arrayWithObjects: #"publish_stream", nil]
defaultAudience: FBSessionDefaultAudienceEveryone
allowLoginUI: YES
completionHandler: ^(FBSession *session,
FBSessionState status,
NSError *error)
{
if (error)
{
NSLog(#"error");
}
else
{
[FBSession setActiveSession:session];
[self setSendButtonTitle: NSLocalizedString(#"Post",#"")];
}
}];
return;
}
// here comes the code you use for sending the message
}
So if the user presses send and the app is not authorized, it will perform a login operation and change your Post button title from "Log in" to "Post". Then the user will be able to post the message by pressing the button once again.
Hope it helps

Get publish permission for Facebook app for iOS with -openWithBehavior:completionHandler:

In my application I need user to sign in to Facebook, get friend list in my table view and Post on feeds, but I don't want to redirect the user anywhere. so I used -openWithBehavior:completionHandler: ... Here is my code.
-(IBAction)loginAction:(id)sender {
[self deleteCookies];
// get the app delegate so that we can access the session property
DLAppDelegate *appDelegate = [[UIApplication sharedApplication]delegate];
// this button's job is to flip-flop the session from open to closed
if (appDelegate.session.isOpen) {
// if a user logs out explicitly, we delete any cached token information, and next
// time they run the applicaiton they will be presented with log in UX again; most
// users will simply close the app or switch away, without logging out; this will
// cause the implicit cached-token login to occur on next launch of the application
[appDelegate.session closeAndClearTokenInformation];
} else {
if (appDelegate.session.state != FBSessionStateCreated) {
// Create a new, logged out session.
appDelegate.session = [[FBSession alloc] init];
[self updateView];
}
// if the session isn't open, let's open it now and present the login UX to the user
[appDelegate.session openWithBehavior:FBSessionLoginBehaviorForcingWebView completionHandler:^(FBSession *session, FBSessionState status, NSError *error) {
switch (status) {
case FBSessionStateOpen:
// call the legacy session delegate
//Now the session is open do corresponding UI changes
{
FBCacheDescriptor *cacheDescriptor = [FBFriendPickerViewController cacheDescriptor];
[cacheDescriptor prefetchAndCacheForSession:session];
[FBSession openActiveSessionWithAllowLoginUI:NO];
[FBSession openActiveSessionWithPublishPermissions:[NSArray arrayWithObjects:#"publish_stream",#"publish_actions", nil] defaultAudience:FBSessionDefaultAudienceFriends allowLoginUI:NO completionHandler:nil];
}
break;
case FBSessionStateClosedLoginFailed:
{ // prefer to keep decls near to their use
// unpack the error code and reason in order to compute cancel bool
// call the legacy session delegate if needed
//[[delegate facebook] fbDialogNotLogin:userDidCancel];
}
break;
// presently extension, log-out and invalidation are being implemented in the Facebook class
default:
break; // so we do nothing in response to those state transitions
}
[self updateView];
}];
}
}
The user is successfully signed in and I can retrieve the friend list by using FQL. The problem is while posting to feeds. I know I need to get publish permissions to do it. But when I uses the following code to post...
- (IBAction)postAction:(id)sender {
DLAppDelegate *appDelegate = [[UIApplication sharedApplication]delegate];
if (appDelegate.session.isOpen) {
[FBSession openActiveSessionWithAllowLoginUI:NO];
NSMutableDictionary *postParams = [[NSMutableDictionary alloc] initWithObjectsAndKeys:
#"https://developers.facebook.com/ios", #"link",
#"https://developers.facebook.com/attachment/iossdk_logo.png", #"picture",
#"Facebook SDK for iOS", #"name",
#"Build great social apps and get more installs.", #"caption",
#"The Facebook SDK for iOS makes it easier and faster to develop Facebook integrated iOS apps.", #"description",
nil];
if ([_postText.text length]>0) {
[postParams setObject:[_postText text] forKey:#"message"];
}
if (([FBSession.activeSession.permissions
indexOfObject:#"publish_actions"] == NSNotFound) ||
([FBSession.activeSession.permissions
indexOfObject:#"publish_stream"] == NSNotFound)) {
// No permissions found in session, ask for it
[FBSession.activeSession
reauthorizeWithPublishPermissions:
[NSArray arrayWithObjects:#"publish_stream",#"publish_actions",nil]
defaultAudience:FBSessionDefaultAudienceFriends
completionHandler:^(FBSession *session, NSError *error) {
if (!error) {
// If permissions granted, publish the story
[self publishStory:postParams];
}
}];
} else {
// If permissions present, publish the story
[self publishStory:postParams];
}
}
}
-(void)publishStory:(NSDictionary *)postParams {
[FBRequestConnection startWithGraphPath:
#"me/feed" parameters:postParams HTTPMethod:#"POST"
completionHandler:^(FBRequestConnection *connection, id result, NSError *error)
{
if (!error) {
//Tell the user that it worked.
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"Shared:"
message:[NSString stringWithFormat:#"Sucessfully posted to your wall."]
delegate:self
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
alertView.tag = 101;
[alertView show];
}
else {
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"Error:"
message:error.localizedDescription
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alertView show];
NSLog(#"%#",error);
}
}
];
}
This code redirects the user to Safari or Facebook App. Which I don't want to happen.
Definitely I need to get publish permissions while logging in. the question is HOW?
You have to set FBSessionLoginBehavior, to change it the only way is to use:
[session openWithBehavior:FBSessionLoginBehaviorWithNoFallbackToWebView
completionHandler:^(FBSession *session,
FBSessionState status,
NSError *error) {
// Respond to session state changes,
// ex: updating the view
}];
I see you use FBSessionLoginBehaviorForcingWebView, so to get what you want you have to choose from this enum:
typedef enum {
/*! Attempt Facebook Login, ask user for credentials if necessary */
FBSessionLoginBehaviorWithFallbackToWebView = 0,
/*! Attempt Facebook Login, no direct request for credentials will be made */
FBSessionLoginBehaviorWithNoFallbackToWebView = 1,
/*! Only attempt WebView Login; ask user for credentials */
FBSessionLoginBehaviorForcingWebView = 2,
/*! Attempt Facebook Login, prefering system account and falling back to fast app switch if necessary */
FBSessionLoginBehaviorUseSystemAccountIfPresent = 3,
} FBSessionLoginBehavior;
Now to solve this "Definitely I need to get publish permissions while logging in. the question is HOW?" you may - (id)initWithPermissions:(NSArray*)permissions; your Session :
NSArray *permissions = #[#"publish_stream", #"publish_actions"];
appDelegate.session = [[FBSession alloc] initWithPermissions:permissions];