Facebook iOS SDK 登录原生和 UIWebView 登录

Posted

技术标签:

【中文标题】Facebook iOS SDK 登录原生和 UIWebView 登录【英文标题】:Facebook iOS SDK login native and UIWebView login 【发布时间】:2013-07-25 23:30:36 【问题描述】:

对于我正在开发的应用程序,我需要用户能够使用本机 SDK 登录 Facebook,但该应用程序还有一个单独的部分使用 web 视图中的 FB cmets 小部件。问题是用户使用本机 SDK 登录后,他们没有在 webview cmets 小部件中登录。有没有办法让用户使用本机 ios SDK 登录,然后在 UIWebView 中将它们登录到 Facebook。我尝试在用户登录后在 FBSession 类中使用 openAccessTokenFromData:completionHandler: 但无法使其正常工作,如下所示

- (void)didLogin

    FBAccessTokenData *data = [FBAccessTokenData createTokenFromString:[FBSession activeSession].accessTokenData.accessToken
                                                       permissions:[FBSession activeSession].accessTokenData.permissions
                                                    expirationDate:[FBSession activeSession].accessTokenData.expirationDate
                                                         loginType:FBSessionLoginTypeWebView
                                                       refreshDate:nil];

    [[FBSession activeSession] closeAndClearTokenInformation];

    FBSession *session = [[FBSession alloc] init];

    [session openFromAccessTokenData:data
               completionHandler:^(FBSession *session, FBSessionState status, NSError *error) 
               ];
    

【问题讨论】:

【参考方案1】:

我使用以下代码在我的本机应用程序的 Webview 中打开 Facebook iOs SDK 登录,它对我来说工作正常。

-(void)openFacebookAuthentication

    NSArray *permission = [NSArray arrayWithObjects:kFBEmailPermission,kFBUserPhotosPermission, nil];

    FBSession *session = [[FBSession alloc] initWithPermissions:permission];

    [FBSession setActiveSession: [[FBSession alloc] initWithPermissions:permission] ];

    [[FBSession activeSession] openWithBehavior:FBSessionLoginBehaviorForcingWebView completionHandler:^(FBSession *session, FBSessionState status, NSError *error) 

        switch (status) 
            case FBSessionStateOpen:
                [self getMyData];
                break;
            case FBSessionStateClosedLoginFailed: 
                // prefer to keep decls near to their use
                // unpack the error code and reason in order to compute cancel bool
                NSString *errorCode = [[error userInfo] objectForKey:FBErrorLoginFailedOriginalErrorCode];
                NSString *errorReason = [[error userInfo] objectForKey:FBErrorLoginFailedReason];
                BOOL userDidCancel = !errorCode && (!errorReason || [errorReason isEqualToString:FBErrorLoginFailedReasonInlineCancelledValue]);


                if(error.code == 2 && ![errorReason isEqualToString:@"com.facebook.sdk:UserLoginCancelled"]) 
                    UIAlertView *errorMessage = [[UIAlertView alloc] initWithTitle:kFBAlertTitle
                                                                           message:kFBAuthenticationErrorMessage
                                                                           delegate:nil
                                                                           cancelButtonTitle:kOk
                                                                           otherButtonTitles:nil];
                    [errorMessage performSelectorOnMainThread:@selector(show) withObject:nil waitUntilDone:YES];
                    errorMessage = nil;
                    
                
                break;
                // presently extension, log-out and invalidation are being implemented in the Facebook class
            default:
                break; // so we do nothing in response to those state transitions
        
    ];
    permission = nil;

【讨论】:

酷,我会尽快尝试并通知您 好的,如果您遇到任何问题,请告诉我。 这会打开一个 webview 进行登录,然后当我使用 uiwebview 转到视图控制器时,我已经登录到 facebook,这很好。问题是,如果我先去 uiwebview 并登录到 facebook,可以将这些数据共享回本机 sdk 吗? 这不是我一直在寻找的,但迄今为止我见过的最佳解决方案,谢谢 @marchinram 关于用户先浏览网页,然后尝试登录 Facebook 的问题,您找到解决方案了吗?【参考方案2】:

创建 facebook Appid Facebook Appid creating link 创建时间遵循 facebook 指南,您必须在注册时提供捆绑标识符

然后使用此代码

@interface LoginViewController : UIViewController<UIWebViewDelegate>
@property(nonatomic,retain)UIWebView *webview;
@property (nonatomic, retain) NSString *accessToken;
@property(nonatomic,retain)UIActivityIndicatorView  *FbActive;
@end
@interface LoginViewController ()

@end

@implementation LoginViewController
@synthesize accessToken,webview,FbActive;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil

    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) 
        // Custom initialization
    
    return self;


- (void)viewDidLoad

    [super viewDidLoad];
    // Do any additional setup after loading the view.

   //Removeing the UIWebview Cookies 
    NSHTTPCookie *cookie;
    NSHTTPCookieStorage *storage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
    for (cookie in [storage cookies]) 
        [storage deleteCookie:cookie];
    
    [[NSUserDefaults standardUserDefaults] synchronize];



-(IBAction)fbLoginPage:(UIButton *)sender1



    NSString   *facebookClientID =facebookAppId;
    NSString   *redirectUri = @"http://www.facebook.com/connect/login_success.html";
    NSString  *extended_permissions=@"user_photos,user_videos,publish_stream,offline_access,user_checkins,friends_checkins,email";

    NSString *url_string = [NSString stringWithFormat:@"https://graph.facebook.com/oauth/authorize?client_id=%@&redirect_uri=%@&scope=%@&type=user_agent&display=touch", facebookClientID, redirectUri, extended_permissions];
    NSURL *url = [NSURL URLWithString:url_string];
    NSURLRequest *request = [NSURLRequest requestWithURL:url];

    CGRect webFrame =[self.view frame];
    webFrame.origin.y = 0;
    UIWebView *aWebView = [[UIWebView alloc] initWithFrame:webFrame];
    [aWebView setDelegate:self];
    self.webview = aWebView;
    self.FbActive = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
    self.FbActive.color=[UIColor darkGrayColor];
    self.FbActive.center = CGPointMake(self.view.frame.size.width / 2, self.view.frame.size.height / 2);
    [self.FbActive startAnimating];

    [webview loadRequest:request];
    [self.webview addSubview:self.FbActive];
    [self.view addSubview:webview];




- (void)webViewDidFinishLoad:(UIWebView *)_webView 

    /**
     * Since there's some server side redirecting involved, this method/function will be called several times
     * we're only interested when we see a url like:  http://www.facebook.com/connect/login_success.html#access_token=..........
     */

    //get the url string
     [self.FbActive stopAnimating];
    NSString *url_string = [((_webView.request).URL) absoluteString];

    //looking for "access_token="
    NSRange access_token_range = [url_string rangeOfString:@"access_token="];

    //looking for "error_reason=user_denied"
    NSRange cancel_range = [url_string rangeOfString:@"error_reason=user_denied"];

    //it exists?  coolio, we have a token, now let's parse it out....
    if (access_token_range.length > 0) 

        //we want everything after the 'access_token=' thus the position where it starts + it's length
        int from_index = access_token_range.location + access_token_range.length;
        NSString *access_token = [url_string substringFromIndex:from_index];

        //finally we have to url decode the access token
        access_token = [access_token stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];

        //remove everything '&' (inclusive) onward...
        NSRange period_range = [access_token rangeOfString:@"&"];

        //move beyond the .
        access_token = [access_token substringToIndex:period_range.location];

        //store our request token....
        self.accessToken = access_token;

        //remove our window
//      UIWindow* window = [UIApplication sharedApplication].keyWindow;
//      if (!window) 
//          window = [[UIApplication sharedApplication].windows objectAtIndex:0];
//      

        [self.webview removeFromSuperview];
         self.webview=nil;



        //tell our callback function that we're done logging in :)
        //      if ( (callbackObject != nil) && (callbackSelector != nil) ) 
        //          [callbackObject performSelector:callbackSelector];
        //      

        //the user pressed cancel

    
    else if (cancel_range.length > 0)
    
        //remove our window
//      UIWindow* window = [UIApplication sharedApplication].keyWindow;
//      if (!window) 
//          window = [[UIApplication sharedApplication].windows objectAtIndex:0];
//      

        [self.webview removeFromSuperview];
        self.webview=nil;

        //tell our callback function that we're done logging in :)
        //      if ( (callbackObject != nil) && (callbackSelector != nil) ) 
        //          [callbackObject performSelector:callbackSelector];
        //      

    
    [self getuserdetailes];



-(void)getuserdetailes

    NSString *action=@"me";

    NSString *url_string = [NSString stringWithFormat:@"https://graph.facebook.com/%@?", action];

    //tack on any get vars we have...

    NSDictionary *get_vars=nil;

    if ( (get_vars != nil) && ([get_vars count] > 0) ) 

        NSEnumerator *enumerator = [get_vars keyEnumerator];
        NSString *key;
        NSString *value;
        while ((key = (NSString *)[enumerator nextObject])) 

            value = (NSString *)[get_vars objectForKey:key];
            url_string = [NSString stringWithFormat:@"%@%@=%@&", url_string, key, value];

        //end while
    //end if

    if (accessToken != nil)
    

        //now that any variables have been appended, let's attach the access token....
        url_string = [NSString stringWithFormat:@"%@access_token=%@", url_string, self.accessToken];
        url_string = [url_string stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
        NSLog(@"%@",url_string);
        NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:url_string]];

        NSError *err;
        NSURLResponse *resp;
        NSData *response = [NSURLConnection sendSynchronousRequest:request returningResponse:&resp error:&err];
        NSString *stringResponse = [[NSString alloc] initWithData:response encoding:NSUTF8StringEncoding];
        NSLog(@"%@",stringResponse);
        NSError* error;
        NSDictionary *FBResResjson = [NSJSONSerialization
                                      JSONObjectWithData:response//1
                                      options:kNilOptions
                                      error:&error];
            NSLog(@"%@",FBResResjson);


    

【讨论】:

【参考方案3】:

感谢 Divya Bhalodiya 回答。这是带有 Facebook SDK 4.x 的 swift 3 版本。如果代码有任何问题,请随时编辑和评论。希望这会有所帮助。

func verifyFromWebView() 
  let fbLoginManager : FBSDKLoginManager = FBSDKLoginManager()
  fbLoginManager.loginBehavior = FBSDKLoginBehavior.web
  fbLoginManager.logIn(withReadPermissions: ["email"], from: self)  (result, error) in
    if error != nil 
        print(error!.localizedDescription)
        self.dismiss(animated: true, completion: nil)
    else if (result?.isCancelled)!
        print("Cancelled")
        self.dismiss(animated: true, completion: nil)
    else

        if let fbLoginResult = result 
            if fbLoginResult.grantedPermissions != nil && fbLoginResult.grantedPermissions.contains("email")

                self.getFBData()

            
        
     
  

【讨论】:

这可以让用户使用原生 SDK 登录,但您仍然需要登录 webview。因此,此解决方案不再适用于解决 OP 问题。

以上是关于Facebook iOS SDK 登录原生和 UIWebView 登录的主要内容,如果未能解决你的问题,请参考以下文章

是否可以在不使用 iOS SDK 的情况下集成 Facebook 登录?

用户更改密码后 Facebook iOS SDK 不会打开登录 UI (iOS 6)

Facebook SDK 原生登录错误

Facebook iOS SDK 3.2 获取用户新闻提要

使用 sdk 4 的 Facebook 自定义登录 UI

iOS Facebook SDK 原生分享