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 登录的主要内容,如果未能解决你的问题,请参考以下文章