1

我正在构建一个在导航栏中有一个导航项的应用程序。

我试图了解单击按钮时如何使用 facebook sdk 连接到 facebook(身份验证)。

这不是一些特殊的视图控制器或其他东西。

我看过这个:http: //developers.facebook.com/docs/tutorials/ios-sdk-tutorial/authenticate/

但是在那里我需要在委托中创建一些我不能使用的东西(比如 UINavigationController),因为我使用的是 UITabBarController..

如何仅通过推送 UINavigationItem 来实现 facebook 登录和会话创建?

这是我的 AppDelegate.h:

#import <UIKit/UIKit.h>
#import <FacebookSDK/FacebookSDK.h>

@interface AppDelegate : UIResponder <UIApplicationDelegate>

@property (strong, nonatomic) UIWindow *window;
@property (strong, nonatomic) UITabBarController *tbc;

@property (strong, nonatomic) FBSession *session;


@end

还有我的 AppDelegate.m:

#import "AppDelegate.h"
#import "StatusView.h"
#import "JokesView.h"
#import "HomeView.h"
#import "TopTenView.h"
#import "UploadView.h"

@implementation AppDelegate

@synthesize tbc;
@synthesize window = _window;
@synthesize session = _session;

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    // Override point for customization after application launch.
    self.window.backgroundColor = [UIColor whiteColor];

    UINavigationController*nav1 = [[UINavigationController alloc]init];
    UINavigationController*nav2 = [[UINavigationController alloc]init];
    UINavigationController*nav3 = [[UINavigationController alloc]init];
    UINavigationController*nav4 = [[UINavigationController alloc]init];
    UINavigationController*nav5 = [[UINavigationController alloc]init];

    StatusView*page1 = [[StatusView alloc]initWithNibName:@"StatusView" bundle:nil];
    JokesView*page2 = [[JokesView alloc]initWithNibName:@"JokesView" bundle:nil];
    HomeView*page3 = [[HomeView alloc]initWithNibName:@"HomeView" bundle:nil];
    TopTenView*page4 = [[TopTenView alloc]initWithNibName:@"TopTenView" bundle:nil];
    UploadView*page5 = [[UploadView alloc]initWithNibName:@"UploadView" bundle:nil];

    page1.title = @"סטטוסים";
    page2.title = @"תמונות";
    page3.title = @"ראשי";
    page4.title = @"Top 10";
    page5.title = @"העלאה";

    UITabBarItem *tab1 = [[UITabBarItem alloc] initWithTitle:@"Status"
                                                       image:[UIImage imageNamed:@"tbc-status.png"] tag:1];
    [nav1 setTabBarItem:tab1];

    UITabBarItem *tab2 = [[UITabBarItem alloc] initWithTitle:@"Jokes"
                                                       image:[UIImage imageNamed:@"tbc-jokes.png"] tag:1];
    [nav2 setTabBarItem:tab2];

    UITabBarItem *tab3 = [[UITabBarItem alloc] initWithTitle:@"Home"
                                                       image:[UIImage imageNamed:@"tbc-home.png"] tag:1];
    [nav3 setTabBarItem:tab3];

    UITabBarItem *tab4 = [[UITabBarItem alloc] initWithTitle:@"Tpp10"
                                                       image:[UIImage imageNamed:@"tbc-topten.png"] tag:1];
    [nav4 setTabBarItem:tab4];

    UITabBarItem *tab5 = [[UITabBarItem alloc] initWithTitle:@"Upload"
                                                       image:[UIImage imageNamed:@"tbc-upload.png"] tag:1];
    [nav5 setTabBarItem:tab5];


    [nav1 pushViewController:page1 animated:NO];
    [nav2 pushViewController:page2 animated:NO];
    [nav3 pushViewController:page3 animated:NO];
    [nav4 pushViewController:page4 animated:NO];
    [nav5 pushViewController:page5 animated:NO];

    tbc = [[UITabBarController alloc]init];
    tbc.viewControllers = [NSArray arrayWithObjects:nav5,nav4,nav3,nav2,nav1, nil];
    tbc.selectedIndex = 2;

    // NavBar Design
    UIImage *navbarPortrait = [[UIImage imageNamed:@"topbar.jpg"]
                               resizableImageWithCapInsets:UIEdgeInsetsMake(0, 0, 0, 0)];
    UIImage *navbarLandscape = [[UIImage imageNamed:@"topbar.jpg"]
                                resizableImageWithCapInsets:UIEdgeInsetsMake(0, 0, 0, 0)];

    [[UINavigationBar appearance] setBackgroundImage:navbarPortrait
                                       forBarMetrics:UIBarMetricsDefault];
    [[UINavigationBar appearance] setBackgroundImage:navbarLandscape
                                       forBarMetrics:UIBarMetricsLandscapePhone];
    // NavBar Design End

    // TabBar Design
    UIImage *tabBackground = [[UIImage imageNamed:@"tbcb3ack.png"]
                              resizableImageWithCapInsets:UIEdgeInsetsMake(0, 0, 0, 0)];
    [[UITabBar appearance] setBackgroundImage:tabBackground];
    [[tbc tabBar] setBackgroundImage:tabBackground];
    // TabBar Design End

    [self.window addSubview:tbc.view];
    self.window.rootViewController = self.tbc;

    // Push Notifications
    [[UIApplication sharedApplication] registerForRemoteNotificationTypes:(UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeNone)];
    // Push Notifications End

    // Facebook Code Start

    //UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Not Logged in"
    //                                                message:@"You Log in to use all the fearues in this app"
    //                                               delegate:nil
    //                                      cancelButtonTitle:@"OK"
    //                                      otherButtonTitles:nil];

    if (FBSession.activeSession.state == FBSessionStateCreatedTokenLoaded) {
        // To-do, show logged in view
    } else {
        //[alert show];

    }

    // Facebook Code End

    [self.window makeKeyAndVisible];
    return YES;

}

// Facebook sdk code Start

- (BOOL)application:(UIApplication *)application
            openURL:(NSURL *)url
  sourceApplication:(NSString *)sourceApplication
         annotation:(id)annotation {
    // attempt to extract a token from the url
    return [FBAppCall handleOpenURL:url
                  sourceApplication:sourceApplication
                        withSession:self.session];
}

// Facebook sdk code End

- (void)applicationWillResignActive:(UIApplication *)application
{
    // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
    // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
}

- (void)applicationDidEnterBackground:(UIApplication *)application
{
    // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 
    // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}

- (void)applicationWillEnterForeground:(UIApplication *)application
{
    // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
}

- (void)applicationDidBecomeActive:(UIApplication *)application
{
    // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}

- (void)applicationWillTerminate:(UIApplication *)application
{
    // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
        [FBAppCall handleDidBecomeActiveWithSession:self.session];
}
#pragma mark Template generated code

@end

这些是在我使用 facebook ios 身份验证教程之后,在实际的 fb 会话更改和登录按钮之前。

4

3 回答 3

3

解决这个问题实际上有两个部分。您首先需要将 UIButton 定义为 UINavigationItem,它将在单击时进行登录(或注销)。其次,您的应用必须准备好接受登录事件。我不确定哪个部分给您带来了更多麻烦,但这是您设置第一部分的方法,即按钮:

UIButton *loginButton = [UIButton buttonWithType:UIButtonTypeCustom];
loginButton.frame = CGRectMake(0.0f, 0.0f, 75.0f, 44.0f);
[loginButton setTitle:@"Login" forState:UIControlStateNormal];
[loginButton addEventHandler:^(id sender)
{
    [FBSession openActiveSessionWithReadPermissions:nil
                                       allowLoginUI:YES
                                  completionHandler:
                                       ^(FBSession *session, 
                                         FBSessionState state, NSError *error) {
                  [self sessionStateChanged:session state:state error:error];
    }];
}
forControlEvents:UIControlEventTouchUpInside];
[self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:loginButton];

至于第二部分,你需要在这个视图控制器中定义 sessionStateChanged 函数。为了节省您的麻烦,以下是 sessionStateChanged 方法所需的一般结构:

- (void)sessionStateChanged:(FBSession *)session 
                      state:(FBSessionState) state
                      error:(NSError *)error
{
    switch (state) {
        case FBSessionStateOpen:
            // Connected to facebook... so go to your next view controller
            break;
        case FBSessionStateClosed:
        case FBSessionStateClosedLoginFailed:
            // Login failed
            [FBSession.activeSession closeAndClearTokenInformation];
            break;
        default:
            break;
    }

    if (error) {
        UIAlertView *alertView = [[UIAlertView alloc]
                     initWithTitle:@"Error"
                           message:error.localizedDescription
                          delegate:nil
                 cancelButtonTitle:@"OK"
                 otherButtonTitles:nil];
        [alertView show];
    }    
}

你还需要实现很多其他的东西,尤其是在你的应用委托中。我很高兴为您编写更多代码示例,但请帮助我了解您接下来想看到的内容。

更新

好的,既然我知道你想让这个 facebook 按钮留在导航栏上,我会将导航控制器子类化,将子类设置为它自己的委托,并将 facebook 按钮添加到每个添加的视图控制器。需要注意的是,绘制的导航栏使用添加到导航控制器的每个视图控制器的 navigationItem。所以从技术上讲,您需要将相同的按钮添加到每个被推入或弹出导航控制器的视图控制器。无需复制粘贴代码,甚至设置所有视图控制器用来插入此 facebook 按钮的实用程序类(或超类),一种快速而肮脏的方法是在导航控制器子类中创建一个按钮并插入它显示与每个视图控制器相同的按钮。

@interface MYNavigationController () <UINavigationControllerDelegate>
@property (nonatomic, strong)           UIButton *facebookButton;
@end

@implementation MYNavigationController

- (void)viewDidLoad
{
    [super viewDidLoad];

    // Set this subclass as its own delegate to be able receive the willShowViewController: method
    self.delegate                       = self;

    // Create a shared facebook button
    _facebookButton = [UIButton buttonWithType:UIButtonTypeCustom];
    _facebookButton.frame = CGRectMake(0.0f, 0.0f, 75.0f, 44.0f);
    [_facebookButton setTitle:@"Login" forState:UIControlStateNormal];
    [_facebookButton
        addTarget:self
        action:@selector(onFacebookButtonClick:)
        forControlEvents:UIControlEventTouchUpInside];
}

- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated
{
    // As each view controller is about to be shown, change the view controller's
    // navigationItem to have this facebook button as its right bar button
    viewController.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:self.facebookButton];
}

- (void)onFacebookButtonClick:(id)sender
{
    // Handle the click event when the facebook button is clicked
    // You need to have logic here to know if the session is open or not
    // Of course, when the session isn't open, then open a new session (ie. login)
    // and when the session IS open, then close the session (ie. logout)
    [FBSession
        openActiveSessionWithReadPermissions:nil
        allowLoginUI:YES
        completionHandler: ^(FBSession *session, FBSessionState state, NSError *error)
        {
            [self sessionStateChanged:session state:state error:error];
        }];
}

- (void)sessionStateChanged:(FBSession *)session state:(FBSessionState)state error:(NSError *)error
{
    switch (state) {
        case FBSessionStateOpen:
            // Connected to facebook so...
            // 1. change the button text to say "logout" instead of "login"
            // 2. go to your next view controller
            break;
        case FBSessionStateClosed:
        case FBSessionStateClosedLoginFailed:
            // Login failed so revert everything to pre-login state
            [FBSession.activeSession closeAndClearTokenInformation];
            break;
        default:
            break;
    }

    if (error) {
        UIAlertView *alertView = [[UIAlertView alloc]
                                  initWithTitle:@"Error"
                                  message:error.localizedDescription
                                  delegate:nil
                                  cancelButtonTitle:@"OK"
                                  otherButtonTitles:nil];
        [alertView show];
    }
}

然后,只需将此 MYNavigationController 用作您的导航控制器类。不要忘记阅读facebook ios 身份验证教程,了解如何设置您的应用程序(有很多框架要添加、infoplist 更改等)。

如果您需要,很乐意提供更多帮助!

更新#2

因为你的窗口的根视图控制器是一个UITabBarController,那么我们可以将它用作 的所有者facebookButton,它在所有UINavigationControllers. 在高层次上,逻辑与我之前的代码示例没有任何变化。您正在某处创建一个按钮,该按钮被添加到导航控制器显示的每个视图控制器中。为了做到这一点,您需要首先创建一个UITabBarController子类(同样,我的称为MYTabBarController,但您可以随意调用它)。它看起来像这样MYTabBarController.m

#import "MYTabBarController.h"
#import <FacebookSDK/FacebookSDK.h>

@implementation MYTabBarController

- (UIButton *)facebookButton
{
    if (! _facebookButton)
    {
        // Create a shared facebook button on demand
        _facebookButton = [UIButton buttonWithType:UIButtonTypeCustom];
        _facebookButton.frame = CGRectMake(0.0f, 0.0f, 75.0f, 44.0f);
        [_facebookButton setTitle:@"Login" forState:UIControlStateNormal];
        [_facebookButton
            addTarget:self
            action:@selector(onFacebookButtonClick:)
            forControlEvents:UIControlEventTouchUpInside];
    }
    return _facebookButton;
}

- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated
{
    // As each view controller is about to be shown, change the view controller's
    // navigationItem to have this facebook button as its right bar button
    viewController.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:self.facebookButton];
}

- (void)onFacebookButtonClick:(id)sender
{
    // Handle the click event when the facebook button is clicked
    // You need to have logic here to know if the session is open or not
    // Of course, when the session isn't open, then open a new session (ie. login)
    // and when the session IS open, then close the session (ie. logout)
    [FBSession
        openActiveSessionWithReadPermissions:nil
        allowLoginUI:YES
        completionHandler: ^(FBSession *session, FBSessionState state, NSError *error)
        {
            [self sessionStateChanged:session state:state error:error];
        }];
}

- (void)sessionStateChanged:(FBSession *)session state:(FBSessionState)state error:(NSError *)error
{
    switch (state) {
        case FBSessionStateOpen:
            // Connected to facebook so...
            // 1. change the button text to say "logout" instead of "login"
            //      eg. [self.facebookButton setTitle:@"Logout" forState:UIControlStateNormal];
            // 2. go to your next view controller
            break;
        case FBSessionStateClosed:
        case FBSessionStateClosedLoginFailed:
            // Login failed so revert everything to pre-login state
            [FBSession.activeSession closeAndClearTokenInformation];
            break;
        default:
            break;
    }

    if (error) {
        UIAlertView *alertView = [[UIAlertView alloc]
                                  initWithTitle:@"Error"
                                  message:error.localizedDescription
                                  delegate:nil
                                  cancelButtonTitle:@"OK"
                                  otherButtonTitles:nil];
        [alertView show];
    }
}

相应的MYTabBarController.h将需要至少定义一个按钮,并且它符合UINavigationControllerDelegate协议:

@interface MYTabBarController: UITabBarController<UINavigationControllerDelegate>

@property (nonatomic, strong)           UIButton *facebookButton;

最后,您的应用程序委托application:didFinishLaunchingWithOptions:需要进行一些小的更改。它需要将标签栏声明为每个 UINavigationControllers 的委托:

// Set the navigation controller delegates to be the tabbar in order to hook into the willShowViewController: method
nav1.delegate                       = tbc;
nav2.delegate                       = tbc;
nav3.delegate                       = tbc;
nav4.delegate                       = tbc;
nav5.delegate                       = tbc;

那应该这样做。希望你能从这里拿走它。祝你好运!

于 2013-06-24T23:16:15.650 回答
0

这是可能的。您可以在 appDelegate 中创建 facebook 登录和会话。当您需要显示 facebook 视图时,您可以调用一个函数来弹出 facebook 视图。

于 2013-06-20T16:23:43.733 回答
0

当你推送到一个 viewController 时,你应该先分配 viewControler。您可以在 viewController 的 alloc 函数中实现 facebook 登录和会话创建。

于 2013-06-20T15:07:26.530 回答