Facebook's FBConnect SDK issues on iOS
Asked Answered
J

6

8

I'm using FBConnect sdk in order to publish posts to a user's profile via my application. I'm having a number of problems with this:

When the relevant code runs for the first time on the device, the user is re-directed, as wanted, to the facebook app/website, which asks him to authorize it. if the user authorizes it, it returns back to the application, which pops a "Connect to facebook" view controller which asks the user to log in. this is weird, as the user is already logged in, otherwise how could he authorize the app? but I guess this may be ok, as he hadn't logged in through the app yet. after he logs in, it does nothing. only the second time the code gets run, after he authorized the app, the user gets the posting dialog.

If the user hadn't authorized the app, when it comes back to my app after the authorization dialog, it asks the user to login ( just as if he authorized ), and does nothing after he had logged in. only the second time the code gets ran, the authorization dialog opens, with the optinos "Authorize" & "Leave App", instead of "Authorize" & "Don't authorize" / "Allow" & "Don't Allow".

In addition, if the user has deleted his authorization via his account's settings on facebook, instead of just asking him to re-authorize it, a facebook dialog pops ( instead of the post/authorization dialog ), saying: "An error occurred. Please try again later." Trying later doesn't help. it will pop always, even if u restart the app. the only way to make it go away is to re-install the app, which will cause it to re-pop the authoriziation dialog.

So here's what I want to achieve:

  1. After the user authorizes the app, he wouldn't have to log in again.
  2. After the user authorizes the app, the posting dialog will pop immedietly, without him having to re-run the code ( which is triggered, btw, with a button ).
  3. If the user un-authorizes the app, he will be prompted again with the authorization dialog, instead of the error dialog
  4. If he refused the authorization, I will call a function that displays an error/etc.

Here's the relevant code:

MyViewController.m

- (void)shareOnFacebook
{
    Facebook *facebook = [[Facebook alloc] initWithAppId:myAppID];
    [(MyAppDelegate *)[[UIApplication sharedApplication] delegate] setFacebook:facebook];
    [facebook release];
    facebook = [(MyAppDelegate *)[[UIApplication sharedApplication] delegate] facebook];
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    if ([defaults objectForKey:@"FBAccessTokenKey"] && [defaults objectForKey:@"FBExpirationDateKey"]) {
        facebook.accessToken = [defaults objectForKey:@"FBAccessTokenKey"];
        facebook.expirationDate = [defaults objectForKey:@"FBExpirationDateKey"];
    }
    if (![facebook isSessionValid]) {
        [facebook authorize:[NSArray arrayWithObjects:@"publish_stream", nil] delegate:(MyAppDelegate *)[[UIApplication sharedApplication] delegate]];
    }

     NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
     //Giving the dictionary some parameters for posting defaults
     [facebook dialog:@"feed" andParams:dictionary andDelegate:self]; //Note: we have 2 different delegates! appDelegate for connections & url switching, and self for dialogs
}

MyAppDelegate.h

@interface MyAppDelegate : NSObject <UIApplicationDelegate, FBSessionDelegate, FBDialogDelegate>
{  
    Facebook *facebook; // kept for facebook sharing, accessed only from MyViewController although delegate methods are handeled in here
}
@property (nonatomic, retain) Facebook *facebook;

@end

MyAppDelegate.m

- (void)fbDidLogin
{
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    [defaults setObject:[facebook accessToken] forKey:@"FBAccessTokenKey"];
    [defaults setObject:[facebook expirationDate] forKey:@"FBExpirationDateKey"];
    [defaults synchronize];
}

- (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url
{
    return [self.facebook handleOpenURL:url];
}

Is it possible that I'm missing a couple of delegate functions on MyViewController? Because I see for some reason I've marked it as implementing the FBDialogDelegate protocol, although he doesn't implement any function from there.

I'd be really glad if you guys would help me, as this is extremely frustrating for me. I couldn't find nothing about this on the internet, and I feel like im drowning in here.

Tnx in advance!

Joijoice answered 17/8, 2011 at 18:1 Comment(1)
It's probably not the answer to your question, but it seems to me one problem you might have is the Facebook instance that's recreated on every share. From the documentation it seems the Facebook instance is generally added to the AppDelegate and never reassigned when the app is running. Perhaps check out this code I wrote for a project I'm working on, it might be easier to solve your issues (it's not perfect yet, but seems to work fine as far as sharing is concerned): #7085662Gusto
C
8

First:

[facebook authorize:[NSArray arrayWithObjects:@"publish_stream",@"offline_access",nil] delegate:self];

The offline_access key here will keep your auth token alive forever (or, more specifically, until the user manually de-authorizes your application in their application settings in their Facebook account settings). Also, set your active VC as the delegate (more on that later).

Secondly:

-(void)popUserShareFeed {
  NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
  //Giving the dictionary some parameters for posting defaults
  [facebook dialog:@"feed" andParams:dictionary andDelegate:self];
}

Call this method (or one like it) in your -fbDidLogin delegate method. Also call it in your original method if the session was still valid, i.e.:

if (![facebook isSessionValid]) {
        [facebook authorize:[NSArray arrayWithObjects:@"publish_stream", nil] delegate:(MyAppDelegate *)[[UIApplication sharedApplication] delegate]];
} else {
  [self popUserShareFeed];
}

...and your new fbDidLogin:

- (void)fbDidLogin
{
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    [defaults setObject:[facebook accessToken] forKey:@"FBAccessTokenKey"];
    [defaults setObject:[facebook expirationDate] forKey:@"FBExpirationDateKey"];
    [defaults synchronize];
    [self popUserShareFeed];
}

(Note: you'll have to define this in MyViewController.m and use it as your FBSessionDelegate. It will be functionally equivalent. Your AppDelegate does not need to also be your FBSessionDelegate.

Third:

Implement the -fbDidNotLogin:(BOOL)cancelled FBSessionDelegate method, like so:

-(void)fbDidNotLogin:(BOOL)cancelled {
   if (cancelled) {
      ... some alert about the user cancelling...
   } else {
      ... some alert about how it failed for some reason...
   }
}

Fourth, as far as your bizarro errors go: A) the Facebook SDKs in general are not great, and B) I'd only set the auth token and the expiration date on your facebook object if

A) you don't already have one instantiated (i.e., it's nil)

and

B) the expirationDate you're setting is in the future (i.e. timeIntervalSinceNow [the NSDate instance method] called on it returns > 0).

Certificate answered 26/8, 2011 at 22:56 Comment(0)
E
3

Sounds like you're experiencing the same issue described in this Facebook Platform Developer forum post. I'm encountering the same problem, but on the web. Only one response was given from Facebook in that thread, and it's wrong information.

Facebook has the worst developer docs and developer support ever, I wouldn't hold my breath waiting on a solution.

Erymanthus answered 18/8, 2011 at 22:0 Comment(0)
A
1

I had similar but not the same problem: message "An error occurred. Please try again later." was shown always.

The problem was with not properly configured App ID - it was provided by customer (so I'm not sure what exactly was wrong); everything works properly since I replaced it with my own test App ID (from previous app).

Amoy answered 27/12, 2011 at 13:13 Comment(0)
H
0

I have integrated FBConnect in so many applications , but never face such kind of critical issue. So, there would be something missing in your code:

Insted of checking FBAccessTokenKey & FBExpirationDateKey, simply try with session object of FBSession class of FBConnect.

Just try using mine code with few conidtions:

session = [[FBSession sessionForApplication:@"key" secret:@"AppSecretKey" delegate:self] retain];
        [session resume];
        _posting = YES;

        // If we're not logged in, log in first...
        if (![session isConnected]) {
            loginDialog = nil;
            loginDialog = [[FBLoginDialog alloc] init]; 
            [loginDialog show]; 
        }
            // If we have a session and a name, post to the wall!
            else if (_facebookName != nil) {
                        [self postToWall]; // Over here posting dialog will appear , if user has already logged in or session is running.
                    }

        }
        else {
            [FBBtn setTitle:@"Login" forState:UIControlStateNormal]; // if you want to change the title of button
            [session logout];
        }

Additionally take care of releasing the session object in dealloc method only , rather than releasing it in any other method.

 - (void)dealloc {
        [super dealloc];
        [session release];
        session = nil;
    }

Hope that would solve your problem.

Holmquist answered 20/8, 2011 at 11:29 Comment(2)
can you provide more code/information? I couldn't find this class. All I got is Facebook, FBDialog, FBLoginDialog and FBRequest.Joijoice
@Joijoice He's using the old facebook SDK - FBConnect. You are using the new one - Facebook iOS SDK.Erlene
R
0

Not a direct solution for your code problems, but...

Have you consider using an open-source library for this? ShareKit is a great example: http://getsharekit.com . The integration is dead simple and it does everything you need.

Royalty answered 26/8, 2011 at 20:31 Comment(1)
I'm getting this error from ShareKit itself (this page was one of the first hits I got on Google, trying to debug ShareKit). ShareKit is terrible - the sum total of the docs for Facebook say "there is no setup for Facebook", which is patently untrue. I would recommend avoiding it - I'm about to switch back to the FB iOS SDK because ShareKit is so appallingly bad.Grievance
K
0

I was having the exact same issue, and used Ben Mosher's response above, but I also decided to create a simple singleton class for the Facebook object, so that in my AppDelegate I can handle the following function properly:

- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url
  sourceApplication:(NSString *)sourceApplication annotation:(id)annotation {

    return [[[FBManager defaultManager] facebook] handleOpenURL:url];

    //return [facebook handleOpenURL:url]; 
}

My singleton class is both FBSessionDelegate and FBDialogDelegate, so it handles the corresponding methods.

This allows me to only prompt the user to login when they are actually trying to post something, instead of when the app launches.

Kif answered 17/11, 2011 at 1:36 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.