Probably I am overlooking something, but I cannot find where I can set the mode in which the extra permissions are requested from the user with the iOS Facebook SDK.
I am requesting additional publishing permissions with the code from below (and yes, I've set facebookLoginView.loginBehavior = FBSessionLoginBehaviorUseSystemAccountIfPresent; for the login), but the extra permission request doesn't pop up in the app, instead it opens up the facebook application. Any idea how to use the built in popup for this request?
if ([[FBSession activeSession] isOpen])
{
NSArray *permissions = [[FBSession activeSession] permissions];
NSArray *newPermissions = #[#"publish_stream"];
if (![permissions containsObject:#"publish_stream"])
{
[[FBSession activeSession] requestNewPublishPermissions:newPermissions defaultAudience:FBSessionDefaultAudienceEveryone completionHandler:^(FBSession *session, NSError *error) {
if (error == nil)
{
[[NSNotificationCenter defaultCenter] postNotificationName:#"FacebookWritePermissionsGranted" object:nil userInfo:nil];
}
}];
}
}
Related
Note: I am following the native login advice from Native Facebook Login stopped working after SDK update to 3.14.
The error is as follows:
2014-10-13 20:03:27.378 Registration[1916:407643] Error
Domain=com.facebook.sdk Code=9 "Access has not been granted to the
Facebook account. Verify device settings." UserInfo=0x1753c630
{NSLocalizedDescription=Access has not been granted to the Facebook
account. Verify device settings., NSLocalizedFailureReason=Access has
not been granted to the Facebook account. Verify device settings.}
This is the code below:
// RegistrationManager.m
- (void)setupFacebook
{
FBSessionStateHandler completionHandler = ^(FBSession *session, FBSessionState status, NSError *error) {
[self sessionStateChanged:session state:status error:error];
};
if ([FBSession activeSession].state == FBSessionStateCreatedTokenLoaded)
{
// we have a cached token, so open the session
[[FBSession activeSession] openWithBehavior:FBSessionLoginBehaviorUseSystemAccountIfPresent
completionHandler:completionHandler];
}
else
{
[self clearAllUserInformation];
// create a new facebook session
FBSession *fbSession = [[FBSession alloc] initWithPermissions:#[#"public_profile"]];
[FBSession setActiveSession:fbSession];
[fbSession openWithBehavior:FBSessionLoginBehaviorUseSystemAccountIfPresent completionHandler:completionHandler];
}
}
- (void)clearAllUserInformation
{
[FBSession.activeSession closeAndClearTokenInformation];
[FBSession renewSystemCredentials:^(ACAccountCredentialRenewResult result, NSError *error) {
NSLog(#"%#", error);
}];
[FBSession setActiveSession:nil];
}
// RegistrationViewController.m
- (IBAction)loginButtonPressed:(id)sender
{
// If the session state is any of the two "open" states when the button is clicked
if (FBSession.activeSession.state == FBSessionStateOpen
|| FBSession.activeSession.state == FBSessionStateOpenTokenExtended)
{
// Close the session and remove the access token from the cache
// The session state handler (in the app delegate) will be called automatically
[FBSession.activeSession closeAndClearTokenInformation];
// If the session state is not any of the two "open" states when the button is clicked
} else
{
FBSessionStateHandler completionHandler = ^(FBSession *session, FBSessionState status, NSError *error) {
[registrationManager sessionStateChanged:session state:status error:error];
};
// create a new facebook session
FBSession *fbSession = [[FBSession alloc] initWithPermissions:#[#"public_profile"]];
[FBSession setActiveSession:fbSession];
[fbSession openWithBehavior:FBSessionLoginBehaviorUseSystemAccountIfPresent completionHandler:completionHandler];
}
}
When I click on the button, it simply says
2014-10-13 20:03:29.560 Registration[1916:407643] Session closed
2014-10-13 20:03:29.561 Registration[1916:407643] User logs out.
2014-10-13 20:03:29.573 Registration[1916:407643] User logs out.
It means that the user once selected "Didn't allow" in the pop-up that asks for permission. If he has his Facebook account linked in Settings, from now on, every time he'll try to login it'll show this error. It won't fallback to Safari or anything, just show this error. The user needs to got into Settings -> Facebook and set the slider for your app to ON.
I want to add Facebook sharing function to my iOS app. I want people can post their feeling about my app on Facebook. Now I can use test users to share successful. But When I use real Facebook account to share, it fails. Xcode says error code:200,error description:(#200) Permissions error.
I passed reviewing of "publish_actions", and I am not in developing mode.
I'm sure my code is right,because I use other people's app secrete to share and it works well.
I don't use Facebook official SDK,and I use ShareSDK.
Most probably in app delegate where you have added permissions you have not requested for all required permissions like following example:
// To open session of facebook and close it
- (BOOL)openSessionWithAllowLoginUI:(BOOL)allowLoginUI {
NSArray *permissions = [[NSArray alloc] initWithObjects:
#"email",
#"user_likes",
#"user_friends",
#"user_about_me",
#"user_relationships",
#"user_birthday",
#"user_location",
nil];
if (! [[FBSession activeSession] isOpen]) {
return [FBSession openActiveSessionWithReadPermissions:permissions
allowLoginUI:allowLoginUI
completionHandler:^(FBSession *session,
FBSessionState state,
NSError *error) {
[self sessionStateChanged:session
state:state
error:error];
}];
}
else {
return [FBSession openActiveSessionWithReadPermissions:permissions
allowLoginUI:allowLoginUI
completionHandler:^(FBSession *session,
FBSessionState state,
NSError *error) {
[self sessionStateChanged:session
state:state
error:error];
}];
}
}
The problem is on ShareSDK.The ShareSDK isn't updated when official Facebook SDK is updated. So I ask for beta ShareSDK to solve the problem.
I am using FB ios SDK v3.5 for my app. For log in part, I don't use FBLoginView to log in, instead, I use a UIButton and invoke [FBSession openActiveSessionWithReadPermission] in the handler of that UIButton.
In FB SDK v3.2.1, I use the following code to handle different log in scenarios, it works fine:
self.useAccountAllowed = true;
ACAccountStore *accountStore;
ACAccountType *accountTypeFB;
if ((accountStore = [[ACAccountStore alloc] init]) &&
(accountTypeFB = [accountStore accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierFacebook] ) ){
NSArray *fbAccounts = [accountStore accountsWithAccountType:accountTypeFB];
id account;
if (!fbAccounts)
{
//do not log into FB on the device
}
else if ([fbAccounts count] == 0) {
[FBSession.activeSession closeAndClearTokenInformation];
self.useAccountAllowed = false; //User does not allow the app to use the account
}
else if ([fbAccounts count]>0 && (account=[fbAccounts objectAtIndex:0])) {
[accountStore renewCredentialsForAccount:account completion:^(ACAccountCredentialRenewResult renewResult, NSError *error) { //User allowes the app to use the account
//we don't actually need to inspect renewResult or error.
if (error){
}
}];
}
}
then in the handler function of the UIButton:
if (self.useAccountAllowed) {
[FBSession openActiveSessionWithReadPermissions:nil allowLoginUI:YES completionHandler:^(FBSession* session, FBSessionState status, NSError* error){
[self sessionStateChanged:session state:status error:error];}];
}
else {
NSArray* lPermission = FBSession.activeSession.permissions;
[FBSession openActiveSessionWithPermissions:lPermission allowLoginUI:YES completionHandler:^(FBSession* session, FBSessionState status, NSError* error){
[self sessionStateChanged:session state:status error:error];}];
which means that if User does not allow the app to use the account, we just use fast-switch way through Safari to login; otherwise we use the native login.
But in SDK v3.5, still the same code, but sometimes when the app is executed and logged into facebook, the app is not in the "Allow these apps to Use your Account" list, so this code cannot distinguish these two cases: 1.the app is not in the list; 2. user disallows the app to use this account. so the app fails to log in natively.
Notice that this problem exists randomly. sometimes I hard code to invoke openActiveSessionWithPermissions directly, this problem is gone. but I am not sure it is the reason.
I just wonder in FB SDK v3.5, do I need to explicitly invoke some SDK function that is related to iOS settings?
I'm using die Facebook SDK 3.1.1 to implement FB Connect in my iOS application. This works fine in the simple case with either the new FB integration (logged in on iOS) or falling back to the normal authorization via web view (I do not have the native Facebook application installed in both cases).
The problem occurs when I switch the account on iOS level. Logging out and logging in with a different FB user account.
To log in/authorize I perform:
[FBSession openActiveSessionWithReadPermissions:nil allowLoginUI:allowLoginUI
completionHandler:^(FBSession *session, FBSessionState state, NSError *error) {
[self sessionStateChanged:session state:state error:error];
}];
If then get a FBSessionStateClosedLoginFailed every time even though I perform a closeAndClearTokenInformation when that state is reached:
- (void)sessionStateChanged:(FBSession *)session
state:(FBSessionState) state
error:(NSError *)error
{
NSLog(#"Session State Changed: %u", [[FBSession activeSession] state]);
switch (state) {
case FBSessionStateOpen:
break;
case FBSessionStateClosed:
case FBSessionStateClosedLoginFailed:
NSLog(#"FBSessionStateClosedLoginFailed ERROR: %#", [error description]);
[[FBSession activeSession] closeAndClearTokenInformation];
break;
default:
break;
}
However, I receive the same state on every retry. My log says the following:
FBSDKLog: FBSession **INVALID** transition from FBSessionStateCreated to FBSessionStateClosed
FBSDKLog: FBSession transition from FBSessionStateCreated to FBSessionStateCreatedOpening
FBSDKLog: FBSession transition from FBSessionStateCreatedOpening to FBSessionStateClosedLoginFailed Session State Changed: 257
FBSessionStateClosedLoginFailed TOKEN: (null)
FBSessionStateClosedLoginFailed ERROR: Error Domain=com.facebook.sdk Code=2 "The operation couldn’t be completed. (com.facebook.sdk error 2.)" UserInfo=0xb24cc20 {com.facebook.sdk:ErrorLoginFailedReason=com.facebook.sdk:ErrorLoginFailedReason}
Can anyone reproduce this or has any idea where the problem might lie?
Another answer gives a way to manually resync the device with the server. I defined a method called fbRsync to call this code. Make sure to #import <Accounts/Accounts.h> in your implementation file and then define this method:
-(void)fbResync
{
ACAccountStore *accountStore;
ACAccountType *accountTypeFB;
if ((accountStore = [[ACAccountStore alloc] init]) && (accountTypeFB = [accountStore accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierFacebook] ) ){
NSArray *fbAccounts = [accountStore accountsWithAccountType:accountTypeFB];
id account;
if (fbAccounts && [fbAccounts count] > 0 && (account = [fbAccounts objectAtIndex:0])){
[accountStore renewCredentialsForAccount:account completion:^(ACAccountCredentialRenewResult renewResult, NSError *error) {
//we don't actually need to inspect renewResult or error.
if (error){
}
}];
}
}
I then call fbResync if openActiveSessionWithReadPermissions yields an error:
[FBSession openActiveSessionWithReadPermissions:permissions
allowLoginUI:YES
completionHandler:^(FBSession *session, FBSessionState state, NSError *error) {
if(error)
{
NSLog(#"Session error");
[self fbResync];
[NSThread sleepForTimeInterval:0.5]; //half a second
[FBSession openActiveSessionWithReadPermissions:permissions
allowLoginUI:YES
completionHandler:^(FBSession *session, FBSessionState state, NSError *error) {
[self sessionStateChanged:session state:state error:error];
}];
}
else
[self sessionStateChanged:session state:state error:error];
}];
The half a second delay is likely unnecessary, but it currently gives me piece of mind.
This seems to solve the problem for me. I can now switch between Facebook accounts and am able to log in. Yay!
I had the same problem. Check that your FB App is enabled in Settings -> Facebook.
Mine was disabled (even though I don't remember disabling it) and once I enabled it, it was fixed.
In my test process, I've added and removed my FB App several times from my FB Account, which is linked with my iPhone. It may explain why, magically, my app was disabled.
In ios 6 with fb sdk 3.1.1. Please pass permissions param as "nil or email" in "[FBSessio openActiveSessionWithReadPermissions..." method. Here my code it was works great.
#define IOS_NEWER_OR_EQUAL_TO_6 ( [ [ [ UIDevice currentDevice ] systemVersion ] floatValue ] >= 6.0 )
-(void)showFBLogin
{
[FBSession.activeSession closeAndClearTokenInformation];
NSArray *permissions = [NSArray arrayWithObjects:#"email, publish_actions, publish_stream", nil];
#ifdef IOS_NEWER_OR_EQUAL_TO_6
permissions = nil; or NSArray *permissions = [NSArray arrayWithObjects:#"email",nil];
#endif
NSLog(#"\npermissions = %#", permissions);
[FBSession openActiveSessionWithReadPermissions:permissions
allowLoginUI:YES
completionHandler:
^(FBSession *session,
FBSessionState state, NSError *error) {
NSLog(#"\nfb sdk error = %#", error);
switch (state) {
case FBSessionStateOpen:
[[FBRequest requestForMe] startWithCompletionHandler:
^(FBRequestConnection *connection, NSDictionary<FBGraphUser> *user, NSError *error) {
if (!error) {
//success
}
}];
break;
case FBSessionStateClosed:
//need to handle
break;
case FBSessionStateClosedLoginFailed:
//need to handle
break;
default:
break;
}
}];
}
I have the same problem on 3.1.3 FB SDK with iOS7.1. And I find a solution here. Hope it help!!
I have tried all answers here.
#loganathan nil permissions, #ill_always_be_a_warriors fbResync.
All of those don't work for me.
But I found it will works well when I launch the same code in iPhone 7.1 simulator
(without SSO"Single Sign On")
The same code works well on old version iOS FB SDK(not sure which version, but not 3.13)
(but no SSO will show when try to login)
So, I try to re-write a sample problem. I found several different here.
1. https://developers.facebook.com/docs/ios/getting-started Add new FacebookDisplayName
2. I modify my BundleID for iTune connect but I am not update it back to Faceboook App Dev
After modify those setting, it works on my iOS app with SSO feature.
Hope it help!!
Did you Try the RenewSystemCredential Methods? Take a look at this post:
Facebook iOS SDK extendAccessToken not Working - fbDidExtendToken not being called
I got the same error. But i used #ill_always_be_a_warriors method: -(void)fbResync but not work for me.
I finally found it's my permissions issue, i removed offline_access permission, it works, hope it helps some one.
If we call openWithBehavior after a call to closeAndClearTokenInformation, it causes EXC_BAD_ACCESS. Regardless of whether it is using the native iOS built-in dialog or one of the fast-switching ones.
Our code to login to FB, first time through works:
if (![FBSession activeSession]) {
#ifdef FREE_APP
NSString* suffix = #"free";
#else
NSString* suffix = #"paid";
#endif
FBSession *session = [[[FBSession alloc] initWithAppID:#"111111111111111"
permissions:permissions
urlSchemeSuffix:suffix
tokenCacheStrategy:nil] autorelease];
[FBSession setActiveSession:session];
}
else if ([FBSession activeSession].isOpen)
[[FBSession activeSession] close];
[[FBSession activeSession] openWithBehavior:FBSessionLoginBehaviorUseSystemAccountIfPresent
completionHandler:^(FBSession *session, FBSessionState state, NSError *error) {
[self sessionStateChanged:session state:state error:error];
}];
Our code to logout, after which the code above fails after openWithBehavior:
[[FBSession activeSession] closeAndClearTokenInformation];
I was initially using openActiveSessionWithReadPermissions instead of openWithBehavior, as prescribed in the 3.1 docs, which does not crash but the app switching back from FB app/Safari did not work. Perhaps because of the need to have a suffix? If it would be easiest to fix the app switching and go back to that, please advise.
Thanks.
When I ran in the 5.x simulator, I saw an extra, very helpful, error message from openWithBehavior, then looked it up in the source which makes things much more clear:
if (!(self.state == FBSessionStateCreated ||
self.state == FBSessionStateCreatedTokenLoaded)) {
// login may only be called once, and only from one of the two initial states
[[NSException exceptionWithName:FBInvalidOperationException
reason:#"FBSession: an attempt was made to open an already opened or closed session"
userInfo:nil]
raise];
}
I've changed my code to always create a fresh session before calling openWithBehavior and it seems happy.
UPDATE:
Here's the updated code that checks for an active session, then closes it, before always instantiating a fresh session...
- (BOOL)openSessionWithAllowLoginUI:(BOOL)allowLoginUI {
if ([FBSession activeSession])
[[FBSession activeSession] closeAndClearTokenInformation];
#ifdef FREE_APP
NSString* suffix = #"free";
#else
NSString* suffix = #"paid";
#endif
NSArray *permissions = [[NSArray alloc] initWithObjects:#"email", nil];
FBSession *session = [[FBSession alloc] initWithAppID:mFacebookID
permissions:permissions
urlSchemeSuffix:suffix
tokenCacheStrategy:nil];
[FBSession setActiveSession:session];
If (allowLoginUI == YES) {
NSLog(#"Calling openWithBehavior");
[[FBSession activeSession] openWithBehavior:FBSessionLoginBehaviorUseSystemAccountIfPresent
completionHandler:^(FBSession *session, FBSessionState state, NSError *error)
{
[self sessionStateChanged:session state:state error:error];
}
];
} else if(session.state == FBSessionStateCreatedTokenLoaded) {
NSLog(#"Calling openWith completion handler");
[session openWithCompletionHandler:^(FBSession *_session, FBSessionState status, NSError *error)
{ [self sessionStateChanged:session state:status error:error];}
];
}
[session release];
return true;
}