简体   繁体   中英

Facebook SDK Singleton in xcode auto login before post?

I have had the Facebook SDK working in the APPDelegate as instructed by the Facebook tutorial, however I am trying to put in into a singleton method. Every tutorial i've found seems to be for an older version of the SDK, but I have managed success with this one http://indiedevstories.com/2011/08/30/a-facebook-reusable-class/

I'm having 2 problems, the first is posted here this is the second:

I want a button to post to Facebook, but if the user isn't logged in then they need to login first then post (without having to press a separate login button first). I can log in fine, and I can post fine, however I can't do both together. If not logged in, the post code shows the login screen, but doesn't goto the post screen after logging in. you have to press post again. If you try to login but are already logged in, then nothing happens. So on the button I use code to login then post, as the login is just skipped if already logged in. The problem i'm having, is the post code is being run instantly after the login code, so before the user has had a chance to login. This results in 2 popups being opened (1 login and 1 post which displays login as not logged in yet).

How can I get my code to wait for the user to login before moving onto the next line in the code to post?

FacebookHelper.h

@interface FacebookHelper : NSObject <FBSessionDelegate, FBRequestDelegate, FBDialogDelegate, FBLoginDialogDelegate> {
    Facebook *_facebook;
    NSArray *_permissions;
}

@property (nonatomic,strong) Facebook *facebook;

+(FacebookHelper *) sharedInstance;
+(void)fbDidLogin;

#pragma mark - Public Methods
-(BOOL) isFBSessionValid;
-(void) login;
-(void) logout;
-(void) postToWallWithDialogNewHighscore:(int)highscore;

@end

FacebookHelper.m

@implementation FacebookHelper
@synthesize facebook;

#pragma mark -
#pragma mark Singleton Variables
static FacebookHelper *singletonDelegate = nil;

#pragma mark -
#pragma mark Singleton Methods

+(FacebookHelper *)sharedInstance
{
    @synchronized(self) {
        if (singletonDelegate == nil) {
            singletonDelegate = [[self alloc] init]; // Assignment not done here
        }
    }
    return singletonDelegate;
}

-(id)init
{
    self = [super init];
    if (self) {
        _facebook = [[Facebook alloc] initWithAppId:kAppId andDelegate:self];
        // Restore previous session
        NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
        if ([defaults objectForKey:@"FBAccessTokenKey"] && [defaults objectForKey:@"FBExpirationDateKey"]) {
        _facebook.accessToken = [defaults objectForKey:@"FBAccessTokenKey"];
        _facebook.expirationDate = [defaults objectForKey:@"FBExpirationDateKey"];
        }
        //
    }
    return self;
}

+(id)allocWithZone:(NSZone *)zone
{
    @synchronized(self) {
        if (singletonDelegate == nil) {
            singletonDelegate = [super allocWithZone:zone];
            // assignment and return on first allocation
            return singletonDelegate;
        }
    }
    //on subsequent allocation attemps, return nil
    return nil;
}

-(id)copyWithZone:(NSZone *)zone
{
    return self;
}

#pragma mark - Facebook Delegate Methods

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

-(void)fbDidLogout
{
    NSLog(@"fbDidLogout");
    // Remove saved authorisation information if it exists
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    if ([defaults objectForKey:@"FBAccessTokenKey"]) {
        [defaults removeObjectForKey:@"FBAccessTokenKey"];
        [defaults removeObjectForKey:@"FBExpirationDateKey"];
        [defaults synchronize];
    }
}

#pragma mark - Public Methods

-(NSMutableDictionary *) buildPostParamsWithHighScore:(int)highscore
{
    NSString *customMessage = [NSString stringWithFormat:kCustomMessage, highscore, kAppName];
    NSString *postName = kAppName;
    NSString *serverLink = [NSString stringWithFormat:kServerLink];
    NSString *imageSrc = kImageScr;

    //Final params build
    NSMutableDictionary *params = [NSMutableDictionary dictionaryWithObjectsAndKeys:
                                   //@"message", @"message",
                                   imageSrc, @"picture",
                                   serverLink, @"link",
                                   postName, @"name",
                                   @" ", @"caption",
                                   customMessage, @"description",
                                   nil];
    return params;
}

-(BOOL) isFBSessionValid
{
    // Check if there is a valid session
    //_facebook = [[Facebook alloc] initWithAppId:kAppId andDelegate:self];
    _facebook.accessToken = [[NSUserDefaults standardUserDefaults] objectForKey:@"FBAccessTokenKey"];
    _facebook.expirationDate = [[NSUserDefaults standardUserDefaults] objectForKey:@"FBExpirationDateKey"];
    NSLog(@"accessToken=%@ expirationDaate=%@",_facebook.accessToken,_facebook.expirationDate);
    if (![_facebook isSessionValid]) {
        NSLog(@"FacebookHelper isFBSessionValid = NO");
        return NO;
    } else {
        NSLog(@"FacebookHelper isFBSessionValid = YES");
        return YES;
    }

    return NO;
}

-(void) login
{
    NSLog(@"FacebookHelper login");
    _permissions = [NSArray arrayWithObjects:@"publish_stream", nil]; //@"read_stream", @"offline_access"
    [_facebook authorize:_permissions];
}

-(void) logout
{
    [_facebook logout];
}

-(void) postToWallWithDialogNewHighscore:(int)highscore
{
    NSMutableDictionary *params = [self buildPostParamsWithHighScore:highscore];

    NSLog(@"Post Feed");
    [_facebook dialog:@"feed" andParams:params andDelegate:self];
}

@end

Button Action:

- (IBAction)facebookTest:(id)sender {
    [[FacebookHelper sharedInstance] login];
    [[FacebookHelper sharedInstance] postToWallWithDialogNewHighscore:123];
}

I have updated the singleton class to post scores to Facebook Wall. Check out the new version: http://indiedevstories.com/2012/04/11/facebookscorer-post-highscores-to-users-facebook-wall/

This new version handles correctly the internal state when authorization and login is required.

HTH

What you need to do is have your postToWallWithDialogNewHighscore call the login, if necessary, and then wait to hear back from the FBSession delegate. Then you need to setup your facebook fbDidLogin delegate so that when it is done it sends back a message. There are a number of ways to do this (a post-login selector, NSNotificationCenter, etc). Something like this should work (note I am assuming an ivar of NSMutableDictionary *postParams for convenience):

-(void)doPost {
    NSLog(@"Post Feed");
    [_facebook dialog:@"feed" andParams:postParams andDelegate:self];
}

-(void)postToWallWithDialogNewHighscore:(int)highscore
{
    postParams = [self buildPostParamsWithHighScore:highscore];
    if (_facebook.isSessionValid) {
        [self doPost];
    } else {
        //register an observer for FB login messages
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(postToWallObserver:) name:@"FBLoginComplete" object:nil];
        [self login];
    }
}

-(void)fbDidLogin {
    NSLog(@"token granted until %@", [_facebook expirationDate]);
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    [defaults setObject:[_facebook accessToken] forKey:@"FBAccessTokenKey"];
    [defaults setObject:[_facebook expirationDate] forKey:@"FBExpirationDateKey"];
    [defaults synchronize];

    [[NSNotificationCenter defaultCenter] postNotificationName:@"FBLoginComplete" object:nil];    
}

-(void)fbDidNotLogin:(BOOL)cancelled {
    //do nothing as they didn't login   
}

-(void) postToWallObserver:(NSNotification *) notification {
    if ([[notification name] isEqualToString:@"FBLoginComplete"]) {
        if ([_facebook isSessionValid]) {
            [self doPost];
        } 
    }
    [[NSNotificationCenter defaultCenter] removeObserver:self];       
}

Note: I have not compiled this code so there may be typos, etc.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM