I'm trying to post to a fan page as the fan page, not as the user.
On the old SDK, I simply asked for "me/accounts" and received the access token. Now I can do the same, but I have no way to use that Token, since FBRequest takes its access token from the active session (also, it's a readonly property).
Does anyone knows how to create another session or simply FBRequests with the page token?
Thanks!
Found a solution, it's not the cleanest, but it's working:
Note: Updated for Facebook SDK 3.2+
- (void)postAsFanPageWithToken:(NSString *)aFanPageToken {
if (self.selectedFanPage == nil) {
self.userAccessToken = [FBSession activeSession].accessTokenData.accessToken;
}
//Using KVC, since it is a readonly property
[[FBSession activeSession].accessTokenData setValue:aFanPageToken forKey:#"accessToken"];
}
- (void)postAsMe {
if (self.userAccessToken == nil) {
return; //Already posting as me
}
[[FBSession activeSession].accessTokenData setValue:self.userAccessToken forKey:#"accessToken"];
self.userAccessToken = nil;
}
// Make sure you cleanup on logout
- (void)logout {
self.userAccessToken = nil;
[[FBSession activeSession] closeAndClearTokenInformation];
}
Related
I'm using facebook-ios-sdk-3.10, Using this SDK I'll login and fetch user details from FB Its working fine for me.
This is the code I'm uisng
- (IBAction)fbLogin_click:(id)sender
{
if (AppDelegate.fbsession.state != FBSessionStateCreated) {
// Create a new, logged out session.
NSArray *permissions = [NSArray arrayWithObjects:#"offline_access", #"email", #"publish_stream", #"read_stream",#"read_friendlists",#"manage_friendlists",#"friends_about_me",#"publish_actions", nil];
// create a session object, with defaults accross the board, except that we provide a custom
// instance of FBSessionTokenCachingStrategy
AppDelegate.fbsession = [[FBSession alloc] initWithAppID:nil
permissions:permissions
urlSchemeSuffix:nil
tokenCacheStrategy:nil];
}
FBSessionLoginBehavior behavior = FBSessionLoginBehaviorForcingWebView;
if (AppDelegate.fbsession.state != FBSessionStateCreatedTokenLoaded) {
// even though we had a cached token, we need to login to make the session usable
[AppDelegate.fbsession openWithBehavior:behavior completionHandler:^(FBSession *session,
FBSessionState status,
NSError *error) {
if (error)
{
NSLog(#"Error");
}
[self GetFBUserDetails];
}];
}
}
-(void) GetFBUserDetails
{
if (AppDelegate.fbsession.isOpen)
{
[HUD show:YES];
// fetch profile info such as name, id, etc. for the open session
FBRequest *me = [[FBRequest alloc] initWithSession:AppDelegate.fbsession graphPath:#"me"];
self.pendingRequest= me;
[me startWithCompletionHandler:^(FBRequestConnection *connection,
NSDictionary<FBGraphUser> *user,
NSError *error) {
// because we have a cached copy of the connection, we can check
// to see if this is the connection we care about; a prematurely
// cancelled connection will short-circuit here
if (me != self.pendingRequest) {
return;
}
self.pendingRequest = nil;
// self.pendingLoginForSlot = -1;
// we interpret an error in the initial fetch as a reason to
// fail the user switch, and leave the application without an
// active user (similar to initial state)
if (error) {
return;
}
[AppDelegate.fbsession closeAndClearTokenInformation];
[FBSession.activeSession close];
[FBSession.activeSession closeAndClearTokenInformation];
FBSession.activeSession=nil;
[self FacebookCustomerRegister:user];
}];
}
}
In such case some user create Facebook account and not very his account through email, when he try to login via my app it shows empty screen after click login button, there is no action further. how can I notify the user "You not yet verify your FB account" and it not return to my app. how can I fetch the response from there ?
can anyone help me for this ?
The email address you get from Facebook using the Graph API or a FQL query is a verified email. If an account hasn't verified it's email yet it's not possible to get it.
so when you fetch user info and if you are not getting the email when you have the permission to get then user is no verified and you can show an alert or any info to user about verifying the email and information
check more detail here Is it possible to check if an email is confirmed on Facebook?
I am working on an iOS app using the latest FB SDK for native log in. When I switch my app off in "allow these apps to use your account" in the settings, an error "com.facebook.sdk error 2" is expected to come.
I am wondering is there any elegant way to solve this error even if "allow these apps to use your account" is off for my app? I have searched for the solution but all the answers are saying that You need to switch that option on. But I think the better way is that if user switches that option off, we can still let him log in, falling back to the fast-app-switch way seamlessly, just like he doesn't log into Facebook on his device at all. How can I do this in the newest FB SDK? Thanks!
====================================Update=========================================
I solve it using a deprecated function openActiveSessionWithPermissions:allowLoginUI:completionHandler
first we need to check whether user switch this option off:
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 switch this option off
}
then in openSession function, using that deprecated function if self.useAccountAllowed is false:
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];}];
not sure whether it is a correct way.
This is how I solved it. On the AppDelegate implementation file, in the applicationDidBecomeActive method, use the regular [FBSession.activeSession handleDidBecomeActive] method, as recommended by the FB SDK documentation. Plus, add a new method that checks the user permissions in Settings (that I called checkPermissionSettings in the example below):
- (void)applicationDidBecomeActive:(UIApplication *)application
{
NSLog(#"applicationDidBecomeActive: in NHOCAppDelegate");
//
// The flow back to your app may be interrupted (for ex: if the user clicks the Home button
// while if authenticating via the Facebook for iOS app).
// If this happens, the Facebook SDK can take care of any cleanup that may include starting a fresh session.
//
[FBSession.activeSession handleDidBecomeActive];
[self checkPermissionSettings];
}
//
// Verify if the user pressed the Home Button, went to Settings and deauthorized the app via "Allow These Apps to Use Your Account..."
// If so, redirect him to the login screen (this happens automagically, see below).
//
- (void)checkPermissionSettings
{
NSLog(#"checkPermissionSettings: in NHOCAppDelegate");
//
// Now 'startForMeWithCompletionHandler' may return 'FBSessionStateClosed' (meaning that the user probably unauthorized the app in Settings).
//
// If that is the case:
//
// - Hide the 'logged' View Controller
// - Remove it (NHOCLoggedVC) from the Notification Center
// - Show the 'login' View Controller
// - And finally add it (NHOCLoginVC) to the Notification Center, closing the loop
//
// Check the console for further info.
//
[FBRequestConnection startForMeWithCompletionHandler:^(FBRequestConnection *connection, id<FBGraphUser> user, NSError *error) {
if (!error) {
//
// Everything went fine... The app is in good shape.
// Notice that 'user.location' requires user_location permission
//
NSLog(#"user.location: %#: ", [user.location objectForKey:#"name"]);
}
}];
}
To make it work as designed, I also use Notification Center. You can check the entire example here:
FB SDK + Storyboards with Publish to Feed
I hope it helps.
I'm testing the new 3.1 framework. If I call [FBSession openActiveSessionWithReadPermissions:allowLoginUI:completionHandler I can see how an UIAlertView is being popped (as I have facebook login in ios).
However, if I create the session on my own and call openWithCompletionHandler I'm redirected to the facebook app or a webview (depending if I have the facebook App installed or not).
Is this broken? Am I missing something?
The reason I don't want to use activeSession, is because I need to set urlSchemeSuffix, and I don't see any way of doing that in activeSession (as these are only being set in the init methods of FBSession).
Thank you
Looking through their code, looks like you need to set a specific behavior to get it to use the system account (this is from the FB SDK):
+ (BOOL)openActiveSessionWithPermissions:(NSArray*)permissions
allowLoginUI:(BOOL)allowLoginUI
allowSystemAccount:(BOOL)allowSystemAccount
isRead:(BOOL)isRead
defaultAudience:(FBSessionDefaultAudience)defaultAudience
completionHandler:(FBSessionStateHandler)handler {
// is everything in good order?
[FBSession validateRequestForPermissions:permissions
defaultAudience:defaultAudience
allowSystemAccount:allowSystemAccount
isRead:isRead];
BOOL result = NO;
FBSession *session = [[[FBSession alloc] initWithAppID:nil
permissions:permissions
defaultAudience:defaultAudience
urlSchemeSuffix:nil
tokenCacheStrategy:nil]
autorelease];
if (allowLoginUI || session.state == FBSessionStateCreatedTokenLoaded) {
[FBSession setActiveSession:session];
// we open after the fact, in order to avoid overlapping close
// and open handler calls for blocks
FBSessionLoginBehavior howToBehave = allowSystemAccount ?
FBSessionLoginBehaviorUseSystemAccountIfPresent :
FBSessionLoginBehaviorWithFallbackToWebView;
[session openWithBehavior:howToBehave
completionHandler:handler];
result = session.isOpen;
}
return result;
}
I'm trying to transition my app to the new Facebook SDK 3.1 (with support for iOS6 authentication).
I had it working just fine, so I then decided to remove the app from my list of authorized apps on the FB website in order to test that iOS would ask for permission again.
Now my first call to [FBRequest requestForMe] causes this error:
Response:
{
"error": {
"message": "Error validating access token: Session does not match current stored session. This may be because the user changed the password since the time the session was created or Facebook has changed the session for security reasons.",
"type":"OAuthException",
"code":190,
"error_subcode":460
}
}
Some details:
I'm trying to open the session as follows :
[FBSession openActiveSessionWithReadPermissions:nil
allowLoginUI:YES
completionHandler:^(FBSession *session, FBSessionState state, NSError *error) {
switch (state) {
case FBSessionStateOpen:
[self presentPostOptions];
break;
case FBSessionStateClosed:
case FBSessionStateClosedLoginFailed:
[FBSession.activeSession closeAndClearTokenInformation];
break;
default:
break;
}
I then get called back in state FBSessionStateOpen (at this point iOS hasn't presented a request dialog, is that to be expected)? Facebook logs this:
2012-09-26 13:43:43.768 MyApp[2177:907] FBSDKLog: FBSession INVALID transition from FBSessionStateCreated to FBSessionStateClosed
2012-09-26 13:43:43.769 MyApp[2177:907] FBSDKLog: FBSession transition from FBSessionStateCreated to FBSessionStateCreatedOpening
2012-09-26 13:43:43.837 MyApp[2177:907] FBSDKLog: FBSession transition from FBSessionStateCreatedOpening to FBSessionStateOpen
Once the session is open, in presentPostOptions I do this:
- (void)presentPostOptions
{
[[FBRequest requestForMe] startWithCompletionHandler:^(FBRequestConnection *connection, NSDictionary<FBGraphUser> *user, NSError *error) {
if (!error) {
self.usersName = user.name;
self.usersID = user.id;
[self getPages];
}
else
{
[self didFailWithError:error];
}
}];
}
Before the above completion block is called back, my main state handler block is called with an FBSessionStateClosed state. In the meantime, the Facebook SDK has logged the above error.
I can't find any way to reset the system; nor do I really understand the cause.
Can anyone please shed some light?
The Facebook account on the device has become out-of-sync with the server as well as with the App's/SDK's cache. This can be solved by calling the ACAccountStore method renewCredentialsForAccount, which will update the OS's understanding of the token state.
In the next update of the SDK, the SDK will automatically call this API when it receives a response from the server indicating that a token has become invalid. For the 3.1.0 revision of the SDK, applications will need to explicitly call this API. Here is a code sample:
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){
}
}];
}
}
There are several options for where/when to call the API. The simplest place would be to opportunistically make the call on application launch, or on view load. One problem with this approach is that it will cause a network round-trip that is often unnecessary. Another option is to call it when a session change notification occurs, indicating that a session has closed. Also many applications fetch some basic information such as graph.facebook.com/me, at application launch time, and if so -- a call to this method in case of an error response may be a reasonable place to ask iOS to update its token status.
Hopefully this helps!
I'm just going to contribute another thing to check that caused me to waste 3 hours:
Make sure your FB app settings do not have the 'Sandbox' option on if you're trying to login with a non-app-developer FB user...
Maybe obvious, but could save others a few hours hopefully.
Try adding, if you haven't already, your iOS App Bundle ID in the settings panel of your Facebook APP as suggested here.
Hope this helps.
[FBSession openActiveSessionWithReadPermissions:nil
allowLoginUI:YES
completionHandler:^(FBSession *session, FBSessionState state, NSError *error)
{
switch (state) {
case FBSessionStateOpen:
[self presentPostOptions];
break;
case FBSessionStateClosed:
case FBSessionStateClosedLoginFailed:
[FBSession.activeSession closeAndClearTokenInformation];
break;
default:
break;
}
}];
I'm fairly sure this is a Facebook iOS SDK bug (even on 3.1.1) and I filed this bug report.
While trying to reproduce this bug using their sample app Scrumptious, I found that it allows you to successfully re-authorize if you are using openActiveSessionWithReadPermissions. However, if you are asking for publish permissions via openActiveSessionWithPublishPermissions, it would be stuck in com.facebook.sdk.error 5.
In facebook SDK 3.7.1 I still had this issue. Basically I have decided to clear the token from the facebook cache when this happens. Like this:
if(state == FBSessionStateClosed ) {
[FBSession.activeSession closeAndClearTokenInformation];
}
Simple Swift 2+ Solution for Facebook Error Validating Access Token
// Step 1: Logout
FBSDKLoginManager().logOut()
// Step 2: Login
FBSDKLoginManager().logInWithReadPermissions(["public_profile", "email"], fromViewController: self, handler: { result, error -> Void in
// ...
}
If this error occurs, you have to create new Facebook Session, so you have to login again.
I am using iOS facebook SDK 3.0. How can i check if the user is already logged in?
I tried the line below but it does not work properly. It sometimes returns NO although I am logged in. Any suggestions?
if (FBSession.activeSession.isOpen == YES)
{
// post to wall else login
}
-- EDIT --
this is how I open my Facebook session:
NSArray *permissions = [[NSArray alloc] initWithObjects:
#"user_likes",
#"read_stream",
#"publish_actions",
nil];
return [FBSession openActiveSessionWithPermissions:permissions
allowLoginUI:allowLoginUI
completionHandler:^(FBSession *session,
FBSessionState state,
NSError *error) {
[self sessionStateChanged:session
state:state
error:error];
}];
The first time it needs login and so it works. If i try this while I am already logged in the FBSession.activeSession.isOpen returns NO.
You can check if you have a valid token by trying to open a new session without allowing the
login UI
if (FBSession.activeSession.isOpen)
{
// post to wall
} else {
// try to open session with existing valid token
NSArray *permissions = [[NSArray alloc] initWithObjects:
#"user_likes",
#"read_stream",
#"publish_actions",
nil];
FBSession *session = [[FBSession alloc] initWithPermissions:permissions];
[FBSession setActiveSession:session];
if([FBSession openActiveSessionWithAllowLoginUI:NO]) {
// post to wall
} else {
// you need to log the user
}
}
If you are using FBSDK greater then 4.x then there is no concept of FBSession. You have to find the active session only by using [FBSDKAccessToken currentAccessToken] simply check if it has nil value, no active session else it is.
Instead, you should check [FBSDKAccessToken currentAccessToken] at
viewDidLoad or similar. If a current token is available, do the
post-login work. You can also use currentAccessToken to retrieve
cached tokens.
you can find more here https://developers.facebook.com/docs/ios/upgrading-4.x
FBSession.activeSession has been replaced with [FBSDKAccessToken currentAccessToken] and FBSDKLoginManager. There is no concept of
session state. Instead, use the manager to login and this sets the
currentAccessToken reference.
i did it as in the Facebook example
if (FBSession.activeSession.state == FBSessionStateCreatedTokenLoaded)
{
}
The session is active if the state is either in FBSessionStateOpen or in FBSessionStateOpenTokenExtended. You can use the function below to check if the user is logged in:
- (BOOL)isSessionOpen
{
return FBSession.activeSession.state == FBSessionStateOpen || FBSession.activeSession.state == FBSessionStateOpenTokenExtended;
}
How are you opening your FBSession?
If you're creating an instance, be sure to set FBSession.activeSession. That was my issue for a while.
if ([FBSDKAccessToken currentAccessToken])
{
NSLog(#"Already login");
//[FBSession openActiveSessionWithAllowLoginUI: YES];
}