我不确定这是否会导致您的问题,但我过去曾遇到过 Facebook SDK 激进缓存的问题。因为 Facebook SDK 会在多个位置查找有效的登录 Facebook 用户,所以它通过缓存当前登录用户来缩短后续调用的搜索。如果在任何时候可能登录的 Facebook 用户之一发生变化,或者该用户的身份验证发生变化,那么事情可能会变得有点疯狂。
为了给你一个想法,Facebook SDK 会尝试 iOS 5+ 系统 facebook 帐户、对 facebook 自己的原生应用程序的应用程序间调用、在你的应用程序中运行的 web 视图实例的浏览器 cookie,或者将你弹回 safari 并使用safari 中的浏览器 cookie ......因此,如果这些不同的登录帐户中的任何一个发生了更改,或者其中一个帐户撤销了权限或更改了其密码(例如),如果 SDK 缓存过于激进,事情就会变得混乱。为了解决这个问题,我总是在打开 Facebook SDK 会话后对照图形 api 检查访问令牌。如果它通过了简单的“我”测试,那么我将接受此访问令牌为有效并继续。但是,如果失败,我会刷新 SDK 中的缓存值并强制 Facebook SDK 重新打开一个全新的会话,这将返回所有可能登录的 Facebook 帐户以查找活动会话。这可能会或可能不会导致新的应用程序身份验证提示......但是它应该会为您的应用程序产生一个有效的访问令牌。
一些示例代码
为了帮助您理解我在做什么,这里有一些半伪代码。(不幸的是,我已经抽象了太多东西,无法在此处轻松复制粘贴一组工作代码,因此您必须在几个地方填写空白:P)
主运行循环
我的 Facebook 代码的入口点以这个 if 语句开头,它查看 Facebook SDK activeSession 的当前状态,并重新提示或验证访问:
if (isSet(FBSession.activeSession) &&
(FBSession.activeSession.isOpen || FBSession.activeSession.state == FBSessionStateCreatedTokenLoaded))
{
// Make sure the access_token is still authed and has the correct permissions first (can't trust what's cached by fb's sdk)
[self checkAgainstGraphAPIOnVerified:^
{
// From the api the access_token looks ready, make sure fb sdk session is open as well
if (FBSession.activeSession.isOpen)
{
// We're authenticated and session is open, good to go
[self runIfFullAuth];
}
else if (FBSession.activeSession.state == FBSessionStateCreatedTokenLoaded)
{
// We have a cached token (permissions all look good), we need to re-open the fb sdk session
[FBSession.activeSession openWithBehavior:FBSessionLoginBehaviorUseSystemAccountIfPresent
completionHandler:openSessionHandler];
}
}
onInvalidated:^
{
// App isn't removed, but don't have required permissions anymore...
if (FBSession.activeSession.isOpen)
{
// We have an open fb session, so just reprompt for permissions
[self repromptForPermissions];
}
else if (FBSession.activeSession.state == FBSessionStateCreatedTokenLoaded)
{
// We have a cached token, we need re-open the session first before reprompting
[FBSession.activeSession openWithBehavior:FBSessionLoginBehaviorUseSystemAccountIfPresent
completionHandler:openSessionHandler];
}
}
onAppRemoved:^
{
// App is completely removed, so prompt for permissions
[self openNewFBSession];
}];
}
else
{
// No valid access_token cached, prompt for permissions
[self openNewFBSession];
}
大多数被调用的函数应该非常简单。例如,runIfFullAuth
在用户完全通过身份验证并且您拥有经过验证的访问令牌后,只需调用您想要的任何内容。 checkAgainstGraphAPIOnVerified:onInvalidated:onAppRemoved:
是我自己的函数,它graph.facebook.com/me?fields=permissions
使用访问令牌进行简单的调用FBSession.activeSession.accessTokenData.accessToken
。如果我在返回的 json 中得到一个 id,那么我就有一个经过验证的访问令牌。如果我在返回的 json 中缺少任何必需的权限,那么我有一个无效的访问令牌。如果我从图形 api 中没有得到任何回报,那么我认为这是应用程序被删除。
openSessionHandler
openSessionHandler
负责了解在我们请求开放会话后 Facebook SDK 返回给我们的内容。这大致是它在做什么:
void(^openSessionHandler)(FBSession *, FBSessionState, NSError *) = ^(FBSession *session, FBSessionState status, NSError *error) {
{
if (error)
{
// Analyze the error
if (error.fberrorShouldNotifyUser)
{
// Pop up alert for error
if ([error.userInfo[FBErrorLoginFailedReason] isEqualToString:FBErrorLoginFailedReasonSystemDisallowedWithoutErrorValue])
{
// App disabled in facebook settings... pop up alert
}
else if ...
else if ...
else if ...
else
{
// Show pop up alert with error.fberrorUserMessage
}
[self runIfNoAuth];
}
else if (error.fberrorCategory == FBErrorCategoryUserCancelled)
{
// User canceled
[self runIfNoAuth];
}
else if (error.fberrorCategory == FBErrorCategoryAuthenticationReopenSession)
{
[self repromptForPermissions];
}
else
{
// Something else happened... probably network issue with Facebook servers
[self runIfNoAuth];
}
}
else
{
switch (status)
{
case FBSessionStateOpen:
{
[self checkAgainstGraphAPIOnVerified:^
{
[self runIfFullAuth];
}
onInvalidated:^
{
[self repromptForPermissions];
}
onAppRemoved:^
{
// If we're here, then we're in a fucked up state. We just prompted the user for auth, and
// the facebook sdk thinks we have an open session, but an api call proves that we're not actually
// authed. A few possible ways to get to this point:
// 1) The multi-screen auth inside facebook's ios app is used (ie. not system facebook account) and
// the user grants general permissions, but before granting posting permission (second page),
// goes to facebook.com and removes application permissions
// 2) The user's facebook account password has changed, and the phone's system facebook account
// hasn't been updated with the new password
// Pop up alert... tell user to check their Facebook settings
[self runIfNoAuth];
}];
break;
}
case FBSessionStateClosed:
case FBSessionStateClosedLoginFailed:
{
[self clearCachedFBInfo];
// If you want, you can choose to reprompt the user for permissions here... but it would most likely result in an endless loop where the only way out is for the user to log in :)
[self runIfNoAuth];
break;
}
default:
break;
}
}
};
clearCachedFBInfo
最后,以下是清除 Facebook SDK 缓存会话信息的方法:
[FBSession.activeSession closeAndClearTokenInformation];
[FBSession.activeSession close];
[FBSession setActiveSession:nil];
老实说,我不知道第二次打电话close
是不是多余的……但我一直都是这样做的……哈哈哈
哦,在我的函数顶部,openNewFBSession
每当我需要强制 Facebook SDK 重新开始并搜索新的 Facebook 会话时,我都会调用它,我调用我的clearCachedFBInfo
函数。这保证了我在 SDK 中没有缓存 Facebook 信息,然后我去打开一个新会话。
最后,我仍然不知道这是否会导致您所看到的问题,但我确实遇到过看似有效的访问令牌在过去无效的非常讨厌的问题,这就是我修复的方法我的问题。祝你好运!我很乐意回答您可能有的任何问题!