1

I'm looking to use the Facebook Api to check in users in an iOS app.

I was wondering if I have the permissions set in the AppDelegate but want the user to checkin from a different view controller do I have to declare the Facebook instance in every view controller along with the FBRequestDelegate, FBSessionDelegate, FBDialogDelegate delegate methods? or is it a one time thing in the AppDelegate?

thanks for any help.

inspector-g
  • 4,146
  • 2
  • 24
  • 33
hanumanDev
  • 6,592
  • 11
  • 82
  • 146

1 Answers1

2

I just dealt with the exact same problem. Here is my solution:

I Created a FBRequestWrapper which basically contains the following methods:

#import <Foundation/Foundation.h>
#import "Facebook.h"

#define FB_APP_ID @"xx"
#define FB_APP_SECRET @"xx"

@interface FBRequestWrapper : NSObject <FBRequestDelegate, FBSessionDelegate>
{
    Facebook *facebook;
    BOOL isLoggedIn;
}

@property (nonatomic, retain) Facebook *facebook;
@property (nonatomic, assign) BOOL isLoggedIn;

+ (id) defaultManager;
- (void) setIsLoggedIn:(BOOL) _loggedIn;
- (void) FBSessionBegin:(id) _delegate;
- (void) FBLogout;
- (void) getFBRequestWithGraphPath:(NSString*) _path andDelegate:(id) _delegate;
- (void) sendFBRequestWithGraphPath:(NSString*) _path params:(NSMutableDictionary*) _params andDelegate:(id) _delegate;

@end

So all the Facebook stuff is managed in this Singleton class.

In my AppDelegate I invoke the authentication. Because in my opinion the authentication has to be done before loading all the controllers.

// FACEBOOK
requestWrapper = [FBRequestWrapper defaultManager];

BOOL loggedIn = [requestWrapper isLoggedIn];

// if the user is not currently logged in begin the session
if (!loggedIn) {
    [requestWrapper FBSessionBegin:(id)self];
} else {
    NSLog(@"Is already logged in!");
}

// Check if the access token is already there. In that case the user is already authenticated with facebook.
// Directly load the controllers and do not wait till facebook has returned back the access_token
if([[NSUserDefaults standardUserDefaults] objectForKey:@"access_token"] != nil &&
   [[NSUserDefaults standardUserDefaults] objectForKey:@"exp_date"] != nil) {
    [self loadControllers];
}

You can see that I also store the accessToken in the NSUserDefaults space. Because we are using the accessToken as authentication to our webservice.

My AppDelegate method is delegating the FBSessionDelegate method:

@interface AppDelegate : UIResponder <UIApplicationDelegate, UITabBarControllerDelegate, FBSessionDelegate>

And here is the implementation of the most important method, fbDidLogin:

- (void) fbDidLogin {
    NSLog(@"AccessToken: %@", requestWrapper.facebook.accessToken);

    [[NSUserDefaults standardUserDefaults] setObject:requestWrapper.facebook.accessToken forKey:@"access_token"];
    [[NSUserDefaults standardUserDefaults] setObject:requestWrapper.facebook.expirationDate forKey:@"exp_date"];
    [[NSUserDefaults standardUserDefaults] synchronize];

    [self loadControllers];
}

Here I store the accesstoken in the NSUserDefaults and load all the Controllers if everything was fine.

Now if you want to access the Facebook Graph Api from any controller outside the AppDelegate you can also use the FBRequestWrapper like that:

- (IBAction)test:(id)sender {
   // FBRequestWrapper
   NSString *graphPath = @"me/friends";

   [[FBRequestWrapper defaultManager] getFBRequestWithGraphPath:graphPath andDelegate:self];
}

Here the code from the FBRequestWrapper.m:

#import "FBRequestWrapper.h"

static FBRequestWrapper *defaultWrapper = nil;

@implementation FBRequestWrapper
@synthesize isLoggedIn, facebook;

+ (id) defaultManager {

    if (!defaultWrapper)
        defaultWrapper = [[FBRequestWrapper alloc] init];

    return defaultWrapper;
}

- (void) setIsLoggedIn:(BOOL) _loggedIn {
    isLoggedIn = _loggedIn;

    if (isLoggedIn) {
        [[NSUserDefaults standardUserDefaults] setObject:facebook.accessToken forKey:@"access_token"];
        [[NSUserDefaults standardUserDefaults] setObject:facebook.expirationDate forKey:@"exp_date"];
        [[NSUserDefaults standardUserDefaults] synchronize];
    }
    else {
        [[NSUserDefaults standardUserDefaults] setObject:@"" forKey:@"access_token"];
        [[NSUserDefaults standardUserDefaults] setObject:@"" forKey:@"exp_date"];
        [[NSUserDefaults standardUserDefaults] synchronize];
    }
}

- (void) FBSessionBegin:(id) _delegate {

    if (facebook == nil) {
        facebook = [[Facebook alloc] initWithAppId:FB_APP_ID andDelegate:_delegate];
        [facebook setSessionDelegate:_delegate];

        NSString *token = [[NSUserDefaults standardUserDefaults] objectForKey:@"access_token"];
        NSDate *exp = [[NSUserDefaults standardUserDefaults] objectForKey:@"exp_date"];

        if (token != nil && exp != nil && [token length] > 2) {
            isLoggedIn = YES;
            facebook.accessToken = token;
            facebook.expirationDate = [NSDate distantFuture];

            [self setIsLoggedIn:isLoggedIn];

            NSLog(@"Access token: %@", facebook.accessToken);
        } 
    }

    if(![facebook isSessionValid]) {
        NSArray *permissions = [NSArray arrayWithObjects:@"offline_access", @"read_friendlists", @"user_about_me", nil];

        // if no session is available login
        [facebook authorize:permissions];
    }
}
- (void) FBLogout {
    [[NSUserDefaults standardUserDefaults] setObject:@"" forKey:@"access_token"];
    [[NSUserDefaults standardUserDefaults] setObject:@"" forKey:@"exp_date"];
    [[NSUserDefaults standardUserDefaults] synchronize];

    [facebook logout:self];
}

// Make simple requests
- (void) getFBRequestWithGraphPath:(NSString*) _path andDelegate:(id) _delegate {
    if (_path != nil) {
        [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];

        if (_delegate == nil)
            _delegate = self;

        if(isLoggedIn) {
            NSLog(@"is logged in in the get method");
        } else {
            NSLog(@"Is NOT logged in the get metthod");
        }

        [facebook requestWithGraphPath:_path andDelegate:_delegate];
    }
}

// Used for publishing
- (void) sendFBRequestWithGraphPath:(NSString*) _path params:(NSMutableDictionary*) _params andDelegate:(id) _delegate {

    if (_delegate == nil)
        _delegate = self;

    if (_params != nil && _path != nil) {

        [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
        [facebook requestWithGraphPath:_path andParams:_params andHttpMethod:@"POST" andDelegate:_delegate];
    }
}

#pragma mark -
#pragma mark FacebookSessionDelegate

- (void)fbDidLogin {
    isLoggedIn = YES;

    [[NSUserDefaults standardUserDefaults] setObject:facebook.accessToken forKey:@"access_token"];
    [[NSUserDefaults standardUserDefaults] setObject:facebook.expirationDate forKey:@"exp_date"];
    [[NSUserDefaults standardUserDefaults] synchronize];
}

- (void)fbDidNotLogin:(BOOL)cancelled {
    isLoggedIn = NO;
}

- (void)fbDidLogout {
    [[NSUserDefaults standardUserDefaults] setObject:@"" forKey:@"access_token"];
    [[NSUserDefaults standardUserDefaults] setObject:@"" forKey:@"exp_date"];
    [[NSUserDefaults standardUserDefaults] synchronize];

    isLoggedIn = NO;
}


#pragma mark -
#pragma mark FBRequestDelegate

- (void)request:(FBRequest *)request didFailWithError:(NSError *)error {
    [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
    //NSLog(@"ResponseFailed: %@", error);
}

- (void)request:(FBRequest *)request didLoad:(id)result {
    [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
    //NSLog(@"Parsed Response: %@", result);
}


/**
 * Called after the access token was extended. If your application has any
 * references to the previous access token (for example, if your application
 * stores the previous access token in persistent storage), your application
 * should overwrite the old access token with the new one in this method.
 * See extendAccessToken for more details.
 */
- (void)fbDidExtendToken:(NSString*)accessToken expiresAt:(NSDate*)expiresAt {
    NSLog(@"Fb did extend token.. NOT IMPLEMENTED YET!");
}

/**
 * Called when the current session has expired. This might happen when:
 *  - the access token expired
 *  - the app has been disabled
 *  - the user revoked the app's permissions
 *  - the user changed his or her password
 */
- (void)fbSessionInvalidated {
    NSLog(@"Fb session invalidated.. NOT IMPLEMENTED YET!");
}

@end
Prine
  • 12,192
  • 8
  • 40
  • 59
  • thanks for your help! does the code you posted // FACEBOOK requestWrapper = [FBRequestWrapper defaultManager]; go in the AppDelegate implementation file or in the FBRequestWrapper.m? I'm a little confused. thanks again :) – hanumanDev Apr 13 '12 at 15:47
  • No problem, this code belongs into the AppDelegate.m file into the following method: - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions. – Prine Apr 13 '12 at 16:28
  • thanks! and the FBRequestWrapper is that it's own class with a .h and .m file? I ask because I'm wondering how else the requestWrapper = [FBRequestWrapper defaultManager]; is declared in the AppDelegate.h file or imported via the FBRequestWrapper.h #import directive in the AppDelegate.m file. – hanumanDev Apr 13 '12 at 21:21
  • Yeah, its an own class with .h, .m file. So its just an import im AppDelegate.m file.. – Prine Apr 14 '12 at 13:48
  • after importing the FBRequestWrapper.h file in the AppDelegate.m file I get the error "Unknown type name 'requestWrapper' for the following: requestWrapper = [FBRequestWrapper defaultManager]; any idea why that would happen? thanks again. – hanumanDev Apr 15 '12 at 21:06
  • 1
    Yes. In my AppDelegate.h file requestWrapper is a class variable. So its defined in the header and in the AppDelegate.m i use synthesize to make the variable accessible. You can do that or just change the line to FBRequestWrapper requestWrapper = [FBRequestWrapper defaultManager]; then its directly defined there.. – Prine Apr 16 '12 at 16:46
  • and the [self loadControllers]; I get "no visible @interface for 'AppDelegate' declares the selector 'loadControllers' everything else appears to be fine. thanks :) – hanumanDev Apr 16 '12 at 17:52
  • Hello friends Is there any updated FBRequestWrapper class for FacebookSDK.framework/FacebookSDK-3.1.1 ? – Wish Jan 08 '13 at 08:43