iOS上Facebook的FBConnect SDK问题

8
我正在使用FBConnect SDK来通过我的应用程序向用户的个人资料发布帖子。我遇到了一些问题:
当相关代码第一次在设备上运行时,用户会被重定向到 Facebook 应用程序/网站,并要求授权。如果用户授权,则返回应用程序,弹出一个“连接到 Facebook”视图控制器,要求用户登录。这很奇怪,因为用户已经登录,否则他如何授权应用程序?但我想这可能没关系,因为他还没有通过应用程序登录。在他登录后,什么也不会发生。只有第二次运行代码,在他授权应用程序之后,用户才会得到发布对话框。
如果用户没有授权该应用程序,则在授权对话框返回我的应用程序后,它会要求用户登录(就像他已经授权一样),并在他登录后什么也不做。只有第二次运行代码时,授权对话框才会打开,其中包括“授权”和“离开应用程序”的选项,而不是“授权”和“不授权”/“允许”和“不允许”。
此外,如果用户通过其 Facebook 帐户的设置删除了授权,而不仅仅是要求他重新授权,Facebook 对话框将弹出(而不是发布/授权对话框),显示“发生错误。请稍后再试。”稍后再试也没有帮助。它将始终弹出,即使您重新启动应用程序。使其消失的唯一方法是重新安装应用程序,这将导致它重新弹出授权对话框。
所以这就是我想要实现的:
1. 用户授权应用程序后,他不需要再次登录。 2. 用户授权应用程序后,发布对话框将立即弹出,而无需重新运行代码(触发按钮)。 3. 如果用户取消授权该应用程序,则会再次提示授权对话框,而不是错误对话框。 4. 如果他拒绝了授权,则会调用一个显示错误等功能的函数。
以下是相关代码:
MyViewController.m
- (void)shareOnFacebook
{
    Facebook *facebook = [[Facebook alloc] initWithAppId:myAppID];
    [(MyAppDelegate *)[[UIApplication sharedApplication] delegate] setFacebook:facebook];
    [facebook release];
    facebook = [(MyAppDelegate *)[[UIApplication sharedApplication] delegate] facebook];
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    if ([defaults objectForKey:@"FBAccessTokenKey"] && [defaults objectForKey:@"FBExpirationDateKey"]) {
        facebook.accessToken = [defaults objectForKey:@"FBAccessTokenKey"];
        facebook.expirationDate = [defaults objectForKey:@"FBExpirationDateKey"];
    }
    if (![facebook isSessionValid]) {
        [facebook authorize:[NSArray arrayWithObjects:@"publish_stream", nil] delegate:(MyAppDelegate *)[[UIApplication sharedApplication] delegate]];
    }

     NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
     //Giving the dictionary some parameters for posting defaults
     [facebook dialog:@"feed" andParams:dictionary andDelegate:self]; //Note: we have 2 different delegates! appDelegate for connections & url switching, and self for dialogs
}

MyAppDelegate.h

@interface MyAppDelegate : NSObject <UIApplicationDelegate, FBSessionDelegate, FBDialogDelegate>
{  
    Facebook *facebook; // kept for facebook sharing, accessed only from MyViewController although delegate methods are handeled in here
}
@property (nonatomic, retain) Facebook *facebook;

@end

MyAppDelegate.m

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

- (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url
{
    return [self.facebook handleOpenURL:url];
}

我可能错过了MyViewController上的一些委托函数吗?因为我看到我将其标记为实现FBDialogDelegate协议,尽管它没有实现那里的任何函数。

如果你们能帮助我,我会非常高兴,因为这对我来说非常令人沮丧。我在互联网上找不到任何关于此事的信息,感觉好像我正在被淹没。

提前感谢!


这可能不是你问题的答案,但我认为你可能遇到的一个问题是每次分享时都会重新创建Facebook实例。从文档中可以看出,Facebook实例通常添加到AppDelegate中,并且在应用程序运行时永远不会被重新分配。也许可以查看一下我为正在开发的项目编写的代码,它可能更容易解决你的问题(它还不完美,但就分享而言似乎工作得很好):https://dev59.com/TlrUa4cB1Zd3GeqPilXw#7085809 - Wolfgang Schreurs
6个回答

8

首先:

[facebook authorize:[NSArray arrayWithObjects:@"publish_stream",@"offline_access",nil] delegate:self];

在这里,“offline_access”关键字将保持您的认证令牌长期有效(或者更明确地说,直到用户在其Facebook帐户设置中手动取消授权您的应用程序)。此外,请将您的活跃VC设置为代表(稍后详细介绍)。

其次:

-(void)popUserShareFeed {
  NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
  //Giving the dictionary some parameters for posting defaults
  [facebook dialog:@"feed" andParams:dictionary andDelegate:self];
}

在您的-fbDidLogin委托方法中调用此方法(或类似的方法)。如果会话仍然有效,则还要在原始方法中调用它,即:

if (![facebook isSessionValid]) {
        [facebook authorize:[NSArray arrayWithObjects:@"publish_stream", nil] delegate:(MyAppDelegate *)[[UIApplication sharedApplication] delegate]];
} else {
  [self popUserShareFeed];
}

...并且您的新 fbDidLogin

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

注意:你需要在MyViewController.m中定义它,并将其用作你的FBSessionDelegate。这将是功能上等效的。你的AppDelegate不需要同时也是FBSessionDelegate
第三步:
实现-fbDidNotLogin:(BOOL)cancelledFBSessionDelegate方法,代码如下:
-(void)fbDidNotLogin:(BOOL)cancelled {
   if (cancelled) {
      ... some alert about the user cancelling...
   } else {
      ... some alert about how it failed for some reason...
   }
}

第四点,关于你的奇怪错误:A)Facebook SDK总体而言并不是很好,B)只有在以下情况下才在你的facebook对象上设置授权令牌和过期日期:
A)如果你没有实例化一个(即它是nil
并且
B)你设置的过期日期是未来的(即调用NSDate实例方法timeIntervalSinceNow返回值大于0)。

3
听起来你正在遇到与这个Facebook平台开发者论坛帖子描述的相同问题。我在网页上遇到了同样的问题。在那个帖子中,Facebook只给出了一个回复,而且是错误的信息。
Facebook拥有最糟糕的开发人员文档和开发人员支持,等待解决方案是不现实的。

1

我遇到了类似但不完全相同的问题:始终显示“发生错误,请稍后再试”的消息。

问题出在未正确配置应用程序ID上 - 这是由客户提供的(所以我不确定具体哪里出了问题);自从我用自己的测试应用程序ID(来自之前的应用程序)替换它以来,一切都正常工作。


0
我遇到了完全相同的问题,并使用了Ben Mosher上面的回答,但我还决定为Facebook对象创建一个简单的单例类,这样在我的AppDelegate中可以正确处理以下函数:
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url
  sourceApplication:(NSString *)sourceApplication annotation:(id)annotation {

    return [[[FBManager defaultManager] facebook] handleOpenURL:url];

    //return [facebook handleOpenURL:url]; 
}

我的单例类同时是FBSessionDelegateFBDialogDelegate,因此它处理相应的方法。

这使我只在用户实际尝试发布内容时提示他们登录,而不是在应用程序启动时提示。


0

我在许多应用程序中集成了FBConnect,但从未遇到过这种关键问题。因此,您的代码可能有些缺失:

请尝试使用FBConnect的FBSession类的会话对象,而不是检查FBAccessTokenKey和FBExpirationDateKey。

只需尝试使用我的代码和几个条件:

session = [[FBSession sessionForApplication:@"key" secret:@"AppSecretKey" delegate:self] retain];
        [session resume];
        _posting = YES;

        // If we're not logged in, log in first...
        if (![session isConnected]) {
            loginDialog = nil;
            loginDialog = [[FBLoginDialog alloc] init]; 
            [loginDialog show]; 
        }
            // If we have a session and a name, post to the wall!
            else if (_facebookName != nil) {
                        [self postToWall]; // Over here posting dialog will appear , if user has already logged in or session is running.
                    }

        }
        else {
            [FBBtn setTitle:@"Login" forState:UIControlStateNormal]; // if you want to change the title of button
            [session logout];
        }

此外,还要注意只在dealloc方法中释放会话对象,而不要在任何其他方法中释放它。
 - (void)dealloc {
        [super dealloc];
        [session release];
        session = nil;
    }

希望能解决你的问题。

你能提供更多的代码或信息吗?我找不到这个类。我只有Facebook、FBDialog、FBLoginDialog和FBRequest。 - Niv
2
@Niv他正在使用旧版的Facebook SDK - FBConnect。而你正在使用新版的Facebook iOS SDK。 - Avi Shukron

0

虽然这不是你代码问题的直接解决方案,但是...

你考虑过使用开源库吗?ShareKit 是一个很好的例子:http://getsharekit.com。它的集成非常简单,而且可以满足你的所有需求。


1
我从ShareKit本身得到了这个错误(这个页面是我在谷歌上搜索调试ShareKit时得到的第一个结果之一)。ShareKit太糟糕了 - Facebook文档的总和说“没有Facebook的设置”,这显然是不正确的。我建议避免使用它 - 我即将切换回FB iOS SDK,因为ShareKit太糟糕了。 - Adam

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接