假設用戶已經登錄與Facebook之前,有[FBSDKAccessToken currentAccessToken] != nil
(我不打算進入細節在這裏,因爲通過FB登錄是另一回事)。
在我的應用程序中,我執行以下操作來確保FB訪問令牌始終有效並與我的應用程序服務器同步。
爲了簡單起見,所有的代碼下面是AppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// ...
/**
Add observer BEFORE FBSDKApplicationDelegate's
application:didFinishLaunchingWithOptions: returns
FB SDK sends the notification at the time it
reads token from internal cache, so our app has a chance
to be notified about this.
*/
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(fbAccessTokenDidChange:)
name:FBSDKAccessTokenDidChangeNotification
object:nil];
return [[FBSDKApplicationDelegate sharedInstance] application: application didFinishLaunchingWithOptions: launchOptions];
}
- (void)fbAccessTokenDidChange:(NSNotification*)notification
{
if ([notification.name isEqualToString:FBSDKAccessTokenDidChangeNotification]) {
FBSDKAccessToken* oldToken = [notification.userInfo valueForKey: FBSDKAccessTokenChangeOldKey];
FBSDKAccessToken* newToken = [notification.userInfo valueForKey: FBSDKAccessTokenChangeNewKey];
NSLog(@"FB access token did change notification\nOLD token:\t%@\nNEW token:\t%@", oldToken.tokenString, newToken.tokenString);
// initial token setup when user is logged in
if (newToken != nil && oldToken == nil) {
// check the expiration data
// IF token is not expired
// THEN log user out
// ELSE sync token with the server
NSDate *nowDate = [NSDate date];
NSDate *fbExpirationDate = [FBSDKAccessToken currentAccessToken].expirationDate;
if ([fbExpirationDate compare:nowDate] != NSOrderedDescending) {
NSLog(@"FB token: expired");
// this means user launched the app after 60+ days of inactivity,
// in this case FB SDK cannot refresh token automatically, so
// you have to walk user thought the initial log in with FB flow
// for the sake of simplicity, just logging user out from Facebook here
[self logoutFacebook];
}
else {
[self syncFacebookAccessTokenWithServer];
}
}
// change in token string
else if (newToken != nil && oldToken != nil
&& ![oldToken.tokenString isEqualToString:newToken.tokenString]) {
NSLog(@"FB access token string did change");
[self syncFacebookAccessTokenWithServer];
}
// moving from "logged in" state to "logged out" state
// e.g. user canceled FB re-login flow
else if (newToken == nil && oldToken != nil) {
NSLog(@"FB access token string did become nil");
}
// upon token did change event we attempting to get FB profile info via current token (if exists)
// this gives us an ability to check via OG API that the current token is valid
[self requestFacebookUserInfo];
}
}
- (void)logoutFacebook
{
if ([FBSDKAccessToken currentAccessToken]) {
[[FBSDKLoginManager new] logOut];
}
}
- (void)syncFacebookAccessTokenWithServer
{
if (![FBSDKAccessToken currentAccessToken]) {
// returns if empty token
return;
}
// BOOL isAlreadySynced = ...
// if (!isAlreadySynced) {
// call an API to sync FB access token with the server
// }
}
- (void)requestFacebookUserInfo
{
if (![FBSDKAccessToken currentAccessToken]) {
// returns if empty token
return;
}
NSDictionary* parameters = @{@"fields": @"id, name"};
FBSDKGraphRequest *request = [[FBSDKGraphRequest alloc] initWithGraphPath:@"me"
parameters:parameters];
[request startWithCompletionHandler:^(FBSDKGraphRequestConnection *connection, id result, NSError *error) {
NSDictionary* user = (NSDictionary *)result;
if (!error) {
// process profile info if needed
}
else {
// First time an error occurs, FB SDK will attemt to recover from it automatically
// via FBSDKGraphErrorRecoveryProcessor (see documentation)
// you can process an error manually, if you wish, by setting
// -setGraphErrorRecoveryDisabled to YES
NSInteger statusCode = [(NSString *)error.userInfo[FBSDKGraphRequestErrorHTTPStatusCodeKey] integerValue];
if (statusCode == 400) {
// access denied
}
}
}];
}
每次你認爲這是檢查FB令牌好時機(例如一個應用程序在後臺了一段時間),撥打-requestFacebookUserInfo
時間。這將提交Open Graph請求,並在令牌無效/過期時返回錯誤。
您可以從網絡獲取當前日期和時間,並根據該日期和時間做出此決定。 – Adeel