As described in the README for facebook-i开发者_开发技巧os-sdk, my app calls Facebook#authorize:delegate: before performing any API calls.
This method requires the user to authenticate (either in the Facebook app or in Safari) and then drops control back to my iPhone app. The problem is it asks the user to authenticate every time I call the method. If they've already granted permission to my app, they get a message saying that the app is already authorized and they have to press Okay to go back to my app. It doesn't look very professional.
So I have two questions:
Does the user always have to reauthorize in order to make Facebook calls? I always thought it would save the access token somewhere, maybe in the user defaults, so that you wouldn't need to reauthorize.
If the user doesn't have to reauthorize every time, is there a way to check if my app already has permission, so the user doesn't have to see that message and press Okay?
It's unfortunate that the Facebook SDK doesn't automatically handle it for us. Aside from building it into the SDK yourself, the easiest way is as such:
Each time you allocate _facebook:
_facebook = [[Facebook alloc] initWithAppId:@"SuperDuperAppID"];
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
NSString *accessToken = [prefs stringForKey:@"facebook-accessToken"];
NSString *expirationDate = [prefs stringForKey:@"facebook-expirationDate"];
_facebook.accessToken = accessToken;
_facebook.expirationDate = expirationDate;
If you've never saved anything in the NSUserDefaults, then nil values will be set. Nothing's happened. Otherwise, true values will be set, and [_facebook isSessionValid];
should return TRUE, indicating good values. Go ahead and make Facebook SDK calls as if they are logged in (which they are). If false, then call
[facebook authorize:permissions delegate:self];
as usual.
Then make sure to support the following Facebook delegate method:
- (void)fbDidLogin {
NSString *accessToken = _facebook.accessToken;
NSString *expirationDate = _facebook.expirationDate;
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
[prefs setObject:accessToken forKey:@"facebook-accessToken"];
[prefs expirationDate forKey:@"facebook-expirationDate"];
[prefs synchronize];
}
I use this code in my app, and it works perfectly. I did this from memory, so I apologize if it doesn't work on copy-and-paste. There might be a mistype somewhere, plus improper memory management. Don't forget that access tokens expire unless you get offline permission. In any case the code above handles everything.
The problem is it asks the user to authenticate every time I call the method. If they've already granted permission to my app, they get a message saying that the app is already authorized and they have to press Okay to go back to my app.
1) Does the user always have to reauthorize in order to make Facebook calls? I always thought it would save the access token somewhere, maybe in the user defaults, so that you wouldn't need to reauthorize.
The cause of having to go through the sign on process every time is that, after successfully signing on the first time, the Facebook SDK doesn't save the access token in a persistent manner.
2) If the user doesn't have to reauthorize every time, is there a way to check if my app already has permission, so the user doesn't have to see that message and press Okay?
The fact that the Facebook SDK doesn't save the access token doesn't mean you can't do it yourself. The following code ilustrates how to save/retrieve the access token from the NSUserDefaults.
-(void)login {
// on login, use the stored access token and see if it still works
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
facebook.accessToken = [defaults objectForKey:ACCESS_TOKEN_KEY];
facebook.expirationDate = [defaults objectForKey:EXPIRATION_DATE_KEY];
// only authorize if the access token isn't valid
// if it *is* valid, no need to authenticate. just move on
if (![facebook isSessionValid]) {
NSArray * permissions = [NSArray arrayWithObjects:@"read_stream", @"offline_access", @"email", nil];
[facebook authorize:permissions delegate:self];
}
}
/**
* Called when the user has logged in successfully.
*/
- (void)fbDidLogin {
// store the access token and expiration date to the user defaults
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:facebook.accessToken forKey:ACCESS_TOKEN_KEY];
[defaults setObject:facebook.expirationDate forKey:EXPIRATION_DATE_KEY];
[defaults synchronize];
}
When the user logs in, you'll get an access token and an expiry date. Save the access token and you can reuse it as long as you haven't hit the expiry date yet. The Facebook SDK has a method to do this check: [fbConnect isSessionValid] but it seems to give false positives sometimes, so I have the user log in if a request fails.
1) No, I had to do Facebook *fbConnect = [[Facebook alloc] init]; [fbConnect logout:self];
to get the user session away
2) I suppose you could call the accestoken in Facebook.m
to check that
Here is more actual approach of @Daniel Amitay answer:
In view controller with login button you write
//saving user data to user defaults in order to support Facebook SSO
let token = FBSDKAccessToken.currentAccessToken()
let prefs = NSUserDefaults.standardUserDefaults()
let nsdataToken = NSKeyedArchiver.archivedDataWithRootObject(token)
prefs.setObject(nsdataToken, forKey: "facebook-AccessToken")
prefs.synchronize()
In AppDelegate file func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool
you write following
//restoring Facebook SSO session from user defaults
let prefs = NSUserDefaults.standardUserDefaults()
if let nsdataToken = prefs.valueForKey("facebook-AccessToken") as? NSData {
let token = NSKeyedUnarchiver.unarchiveObjectWithData(nsdataToken) as! FBSDKAccessToken
FBSDKAccessToken.setCurrentAccessToken(token)
}
精彩评论