I'm using iOS SDK 3.1.1 and trying to get both read and publish permission at once.
As tutorial says, I'm calling FBSession openActiveSessionWithReadPermissions and in its handler - handler A - call [[FBSession activeSession] reauthorizeWithPublishPermissions only if handler A is called with session state of FBSessionStateOpen.
When I have facebook account is set in iOS 6's setting, reauthorizeWithPublishPermissions's handler - handler B - is called normally, with error argument of nil.
However, if I don't have facebook account set in iOS 6's setting, handler B is called with reauth error named "ErrorReauthorizeFailedReasonUserCancelled" when app is switched to Safari to gain publish permission.
More weird thing is this. In both cases before handler B is called, handler A is called with session state of FBSessionStateOpenTokenExtended.
Are these normal or expected behavior of new SDK? If so, should I not check if error is nil in handler B?
happened to me and after searching a while I found a solution for that. You have to call reauthorizeWithPublishPermissions in dispatch_async in the handler A of openActiveSessionWithReadPermissions:
dispatch_async(dispatch_get_current_queue(), ^{
[[FBSession activeSession] reauthorizeWithPublishPermissions:permissions
defaultAudience:FBSessionDefaultAudienceEveryone
completionHandler:^(FBSession *session, NSError *error) {
// handle the flow here
}];
});
Related
I'm implementing OAuth login using Facebook SDK, but the FBSession.openActiveSessionWithReadPermissions:allowLoginUI:completionHandler method is not calling the completionHandler nor is it returning "true", which would indicate a cached token. Everything else seems to work fine, except this. What's wrong with this code?
var completionHandler: FBSessionStateHandler = {
session, status, error in
NSLog("token not cached");
if error {
// Login failed for some reason, so we notify the delegate.
self.delegate.didFailOpenningSession?(self, withError: ErrorUtility.error(
code: .FailedOpenningSession,
withFacebookError: error
));
// Don't proceed on errors
return;
}
// Session is now open, we should notify the delegate
self.delegate.didOpenSession?(self);
};
NSLog("here");
// Open the session, prompting the user if necessary. This might send the application to the background
if FBSession.openActiveSessionWithReadPermissions(["public_profile"], allowLoginUI: true, completionHandler: completionHandler) {
NSLog("Token cached");
// If we end up here, the session token must exist, so we now have an open session
self.delegate.didOpenSession?(self);
}
Edit: I forgot to mention that the NSLog logs "here", but not "Token cached" nor "token not cached"
Edit: Now things got a bit stranger. When my app launches I show a screen with a Facebook login button. When the user presses the button the code above gets triggered. After I authorise the app, the app gets back to the same screen (it shouldn't, but I can't do it any other way until the completion handler gets called). Then I tried pressing the button again and now I do get the logs.
This is what I get:
here
token not cached
here
The first line is from the first button press, the other two appear when I press it the second time. Now what's so odd about it? Shouldn't "token not cached" and "here" be reversed??? Is it calling the competionHandler from the last call or something?
Nevermind, that much is fixed.
Edit: one other thing. If I press the button multiple times, I always get "token not cached". I think it should be caching
It's solved. I was missing the method AppDelegate.application:handleOpenURL -> Bool
First ensure that you are using correct closure syntax. You are not providing a matching closure callback for the block callback.
notice the block callback for the FB session is:
^(FBSession *session,
FBSessionState state, NSError *error)
You should have
/*function parameters*/){ session, state, error in
//closure declaration goes at the top after the {
//Insert logic here
NSLog("Token cached");
}
This will equate to
FBSession.openActiveSessionWithReadPermissions(permissions, allowLoginUI:true){ session, state, error in
//callback code body here
}
This usually because of missing handle seesion in app’s application:openURL function.
It is in AppDelegate.m. Description from facebook samples says below:
// During the Facebook login flow, your app passes control to the Facebook iOS app or Facebook in a mobile browser.
// After authentication, your app will be called back with the session information.
// Override application:openURL:sourceApplication:annotation to call the FBsession object that handles the incoming URL
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication
annotation:(id)annotation
{
return [FBSession.activeSession handleOpenURL:url];
}
I am observing the following....
I authenticate a user via the following (note that in the completion block I am nslogging the permissions)
NSArray *permissions = [[NSArray alloc] initWithObjects:
#"email", #"publish_actions",
nil];
[FBSession openActiveSessionWithPublishPermissions:permissions
defaultAudience:FBSessionDefaultAudienceFriends
allowLoginUI:allowLoginUI
completionHandler:^(FBSession *session, FBSessionState state, NSError *error) {
NSLog(#"permissions %#",FBSession.activeSession.permissions);
}];
As a user I start up the app and proceed to login w/ FB.
I am presented with a screen that reads "app would like to access your public profile, friend list and email address." and I select "ok"
I am presented with a screen that reads "app would like to post to your friends on your behalf" and I select "skip".
3) The completion block code spits out the permissions as the following
permissions (
email,
"publish_actions"
)
Why is publish_actions listed? If I try to post to FB now through the app it will error out and tell me that I don't have the right permissions......yet I cannot check for this case b/c FBSession.activeSession.permissions tells me that I have the "publish_actions" permission even when in reality I do not.
What am I missing here?
If you were using iOS SDK 3.0, then this was due to a bug in the SDK. See the bug report for more details.
Symptom summary:
After authorizing user with openActiveSessionWithPermissions method, the sessions variable in callback method contains extended permissions that were not allowed by a user.
I've been having this issue and can't find anything on it. I'm using the Social framework to build a basic Twitter application (a learning project for myself) and haven't run into any major roadblocks until just recently when the account store stopped completing my requests for account access. From all the samples I've read and gathered, when the application starts I request access to the accounts and then once granted can go from there.
The code I have to fetch the accounts is:
ACAccountType* accountType = [self.accountStore accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierTwitter];
NSLog(#"Making this call to getTwitterAccount");
[self.accountStore
requestAccessToAccountsWithType:accountType
options:nil
completion:^(BOOL granted, NSError* error) {
NSLog(#"Testing, this should show up");
if (granted) {
NSArray* accounts = [self.accountStore accountsWithAccountType:accountType];
[self getAccountFromArray:accounts];
}
else {
if (error.code == 6)
NSLog(#"No twitter account");
else
NSLog(#"Access denied");
}
}];
The two NSLog statements are in there for debugging purposes. I call the function that contains this code from viewDidLoad and the getAccountFromArray:(NSArray*) function simply determines if which account the user wishes to use for the application (presenting a modal view if necessary). My issue is with the completion block never being called unless I make a change to the accounts in the simulator. Immediately following a change to the accounts and the code executes and displays the modal (which for now just says a message) but for any other execution this block is never fired and the only print seen in the console is "Making this call to getTwitterAccount". Previously, this worked fine for fetching a single account and I was able to get the timeline fetch working and printing but then it stopped firing for some reason and I haven't been able to make a success SLRequest or do any other actions based on it since.
I've Googled and found problems with using this function out there but none of those issues are with the completion block never firing.
EDIT
Okay so an update, been working at this and for some reason moving the call to the function that checks accounts into the views initWithNibName:bundle: method seemed to work, it executes reliably (albeit a tad after the app loads). The function is called twice but only executes the completion once and only when I call it from the init - maybe a reason for this?
I am trying to add the "select friends" to my iOS app. I set up the login view. Once I login I open the friend picker but it comes up blank. I see the table with the done and cancel buttons but there are no friends loaded into the table.
- (IBAction)selectFriendsButtonAction:(id)sender {
if (self.friendPickerController == nil) {
// Create friend picker, and get data loaded into it.
self.friendPickerController = [[FBFriendPickerViewController alloc] init];
self.friendPickerController.title = #"Select Friends";
self.friendPickerController.delegate = self;
}
[self.friendPickerController loadData];
[self.friendPickerController clearSelection];
[self presentViewController:self.friendPickerController animated:YES completion:nil];
}
Prior to opening the friend picker controller ensure your Facebook session is active by calling this:
if (!FBSession.activeSession.isOpen) {
// if the session is closed, then we open it here, and establish a handler for state changes
[FBSession.activeSession openWithCompletionHandler:^(FBSession *session,
FBSessionState state,
NSError *error) {
// Handle error
}];
}
There's two things you need to take care of that you may well not realize you need even if you understand the rest of the Facebook SDK pretty well.
The dialog will only show friends that have also installed the app.
You have to ask for the user_friends permission during your login flow.
For 1., create or use a test user you already have and run your app with that user in order to authorize the app for basic access ("install" it).
For 2, add that permission to your login flow, log out and back in with the sender you're testing (probably your own user), and if you don't get prompted to grant it even then, uninstall the app via https://www.facebook.com/settings/?tab=applications.
http://www.brianjcoleman.com/tutorial-get-facebook-friends-in-swift/ discusses some of this. The Facebook docs themselves either don't mention the 2 issues at all or it's buried.
If you use "FBFriendPickerViewController", it seems return friends who also use this APP. In Facebook document: after API Graph v2.0, "me/friends" will only return friends that also use the app. I think that's why the friend table is blank.
There is another option that you can use "FBTaggableFriendPickerViewController" instead. But your APP will need to be reviewed by Facebook before it can get data back. (https://developers.facebook.com/docs/graph-api/reference/v2.2/user/taggable_friends?locale=zh_TW)
I am using Facebook iOS SDK 3.1.1 and has been successfully integrated a lot of Facebook features. Adhering to 3.1.1, I am logging in using
[FBSession openActiveSessionWithPermissions:permission
allowLoginUI:bAllowLoginUI
completionHandler:^(FBSession *session, FBSessionState state, NSError *error) {
[self sessionStateChanged:session state:state error:error];
}];
Then I need to send "apprequests", and there is no new method to implement in SDK 3.1, so I've to fallback to the deprecated API using Facebook objects and FBDialog.
However, calling the deprecated dialog function:
[m_pFacebook dialog:#"apprequests"
andParams:params
andDelegate:delegate];
results in the FBDialog popping up and prompting the user to login again through the dialog. I need to go directly to the apprequests dialog without needing the user to input their credentials again and I am sure there's a way to do it as I've seen it implemented in Diamond Dash and other games.
I've tried setting the m_pFacebook.accessToken with FBSession.activeSession.accessToken, and I have also make sure that m_pFacebook.session is filled with the FBSession's logged in session
Anyone encountered this problem before?
After some debugging, figured out that the expirationDate of Facebook *m_pFacebook object has not been updated, therefore the _lastAccessTokenUpdate is still in [NSDate distantPast]. The solution is to call
[m_pFacebook fbDialogLogin:session.accessToken expirationDate:session.expirationDate];
when sessionStateChanged to FBSessionStateOpen
- (void) sessionStateChanged:(FBSession*)session state:(FBSessionState)state error:(NSError*)error {
switch ( state ) {
case FBSessionStateOpen:
[m_pFacebook fbDialogLogin:session.accessToken expirationDate:session.expirationDate];
break;
}
}