How can I get UIWebView to open Facebook login page in response to the OAuth request on iOS 5 and iOS 6?

后端 未结 5 1303
Happy的楠姐
Happy的楠姐 2020-12-15 13:30

We have:
(1) Facebook API-based web application with Facebook OAuth functionality (“the FB web app”)
(2) UIWebView-based browser on iPad (“the Browser”

相关标签:
5条回答
  • 2020-12-15 13:51

    How to facebook login in UIWebView.

    Objective-c

    Use taylorstine's answer. He saved my day. Thank you taylorstine

    But I'm using Swift 3. so I just converted code below from taylorstine's answer.

    Swift 3.

    func webView(_ webView: UIWebView, shouldStartLoadWith request: URLRequest, navigationType: UIWebViewNavigationType) -> Bool {
    
        if let _ = request.url?.absoluteString.range(of: "m.facebook.com" ) {
            if let _ = request.url?.absoluteString.range(of: "back"){
                self.popUp?.removeFromSuperview()
                self.popUp = nil
                return false
            }
    
            if let _ = self.popUp {
                return true
            }
    
            let wv = popUpWebView()
            wv.loadRequest(request)
    
            return false
        }
    
        return true
    }
    
    func popUpWebView() -> UIWebView {
    
        let webView = UIWebView(frame: self.view.frame)
    
        webView.delegate = self
        self.popUp = webView
        self.view.addSubview(webView)
    
        return webView
    }
    
    func webViewDidFinishLoad(_ webView: UIWebView) {
        if let _ = self.popUp {
    
            let jsFromFile = "window.close=function(){window.location.assign('back://' + window.location);};"
    
            let _ = webView.stringByEvaluatingJavaScript(from: jsFromFile)
    
            let openerContext = self.webView.value(forKeyPath: "documentView.webView.mainFrame.javaScriptContext") as! JSContext
    
            let popupContext = webView.value(forKeyPath: "documentView.webView.mainFrame.javaScriptContext") as! JSContext
    
            popupContext.setObject("opener", forKeyedSubscript: "window" as (NSCopying & NSObjectProtocol)!)
            popupContext.setObject(openerContext.objectForKeyedSubscript("window"), forKeyedSubscript: "opener"  as (NSCopying & NSObjectProtocol)!)
    
        }
    
        if webView == self.popUp
            && (webView.request?.url?.absoluteString.range(of:"m.facebook.com") != nil)
            && webView.stringByEvaluatingJavaScript(from: "document.body.innerHTML") == "" {
    
            webView.stringByEvaluatingJavaScript(from: "eval(document.getElementsByTagName('script')[0].text)")
    
        }
    
    }
    
    0 讨论(0)
  • 2020-12-15 13:57

    Use the FBDialog class to prompt the user to login. This uses a webview inside of the app, therefore on successful login the user will be logged in inside of any UIWebView:

    NSString *kRedirectURL  = @"fbconnect://success";
    NSString *kSDK = @"ios" ;
    NSString *kLogin = @"oauth";
    NSString *kDialogBaseURL = @"https://m.facebook.com/dialog/";
    
    NSMutableDictionary* params = [NSMutableDictionary dictionaryWithObjectsAndKeys:
                                   AE_FACEBOOK_APPID, @"client_id",
                                   @"user_agent", @"type",
                                   kRedirectURL, @"redirect_uri",
                                   @"touch", @"display",
                                   kSDK, @"sdk",
                                   nil];
    
    NSString *loginDialogURL = [kDialogBaseURL stringByAppendingString:kLogin];
    
    FBLoginDialog* loginDialog = [[FBLoginDialog alloc] initWithURL:loginDialogURL
                                                        loginParams:params
                                                           delegate:self];
    [loginDialog show];
    

    Then make your class adhere to the FBDialogDelegate protocol, and add this function to your class:

    -(void)fbDialogLogin: (NSString *)token expirationDate:(NSDate *)expirationDate{
        // Store the token and expiration date into the FB SDK
        self.facebook.accessToken = token;
        self.facebook.expirationDate = expirationDate;
        // Then persist these so the SDK picks them up on next load
    
        NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
    
    [defaults setObject:self.facebook.accessToken forKey:ACCESS_TOKEN_KEY];
    [defaults setObject:self.facebook.expirationDate forKey:EXPIRATION_DATE_KEY];
    [defaults synchronize];
    }
    

    HTH!

    0 讨论(0)
  • 2020-12-15 13:59

    just use : this code

    if (![FBSDKAccessToken currentAccessToken]) 
    {   
        FBSDKLoginManager *manager = [[FBSDKLoginManager alloc]init];
        manager.loginBehavior = FBSDKLoginBehaviorWeb;
        [manager logInWithReadPermissions:@[@"public_profile", @"email", @"user_friends"] handler:
         ^(FBSDKLoginManagerLoginResult *result, NSError *error) {
    
             NSLog(@"result.token: %@",result.token.tokenString);  
             NSLog(@"%@",result.token.userID);   
             NSLog(@"%hhd",result.isCancelled);     
         }];
    }
    

    // here manager.loginBehavior = FBSDKLoginBehaviorWeb; is all you need to open facebook in UIWebview

    0 讨论(0)
  • 2020-12-15 13:59

    Did it!

    It kinda of a hack, but the js facebook sdk login on UiWebView at iOS 6 finally works.

    How it could be done? It is a pure JS + Facebook JS SDK + UIWebView Delegate handling functions solution.

    JS - First step)

    a login button (to connect with facebook) calls this function example, that will trigger Face JS login/oauth dialogs:

    function loginWithFacebookClick(){
    
    FB.login(function(response){
        //normal browsers callback 
    });
    
    }
    

    JS - Second step)

    add a authResponseChange listener every time user loads the webpage ( after FB.init() ) to catch user's connected status:

    FB.Event.subscribe('auth.authResponse.Change', function(response){
    //UIWebView login 'callback' handler
    var auth = response.authResponse;
    if(auth.status == 'connected'){
        //user is connected with facebook! just log him at your webapp
    }
    });
    

    AND with app's UIWebView delegate functions you can handler facebook oauth responses

    Objective C - Third step)

    - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
    {
    NSString *url = [[request URL] absoluteString];
    
    //when user status == connected (has a access_token at facebook oauth response)
    if([url hasPrefix:@"https://m.facebook.com/dialog/oauth"] && [url rangeOfString:@"access_token="].location != NSNotFound)
    {
        [self backToLastPage];
        return NO;
    }
    
    return YES;
    }
    
    - (void)webViewDidFinishLoad:(UIWebView *)webView
    {
    
    NSString *url = [[webView.request URL] absoluteString];
    
    if([url hasPrefix:@"https://m.facebook.com/dialog/oauth"])
    {
        NSString *bodyHTML = [webView stringByEvaluatingJavaScriptFromString:@"document.body.innerHTML"];
    
        //Facebook oauth response dead end: is a blank body and a head with a script that does 
        //nothing. But if you got back to your last page, the handler of authResponseChange
        //will catch a connected status if user did his login and auth app
        if([bodyHTML isEqualToString:@""])
        {
            [self backToLastPage];
        }
    }
    
    }
    

    So, when 'redirect' user to the last loaded page, the second step is going to handler user action at facebook login dialogs.

    If I got too fast with this answer, please ask me! Hope it helps.

    0 讨论(0)
  • 2020-12-15 14:08

    In case anyone is googling, here's what worked for me:

    -(BOOL) webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)inType {
        if ([request.URL.absoluteString containsString:@"m.facebook.com"]) {
            if ([request.URL.absoluteString rangeOfString:@"back"].location == 0) {
                [self.popUp removeFromSuperview];
                self.popUp = nil;
                return NO;
            }
            if (self.popUp) {
                return YES;
            }
    
            UIWebView *wv = [self popUpWebView];
            [wv loadRequest:request];
            return NO;
        }
        return YES;
    }
    
    - (UIWebView *) popUpWebView {
        toolbar height
        UIWebView *webView = [[UIWebView alloc]
                initWithFrame:CGRectMake(0, 0, (float)self.view.bounds.size.width,
                        (float)self.view.bounds.size.height)];
        webView.scalesPageToFit = YES;
        webView.delegate = self;
        // Add to windows array and make active window
        self.popUp = webView;
        [self.view addSubview:webView];
        return webView;
    }
    
    - (void)webViewDidFinishLoad:(UIWebView *)webView {
    
        if (self.popUp) {
            NSError *error = nil;
            NSString *jsFromFile = @"window.close=function(){window.location.assign('back://' + window.location);};";
            __unused NSString *jsOverrides = [webView
                    stringByEvaluatingJavaScriptFromString:jsFromFile];
    
            JSContext *openerContext = [self.webView
                    valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
            JSContext *popupContext = [webView
                    valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
            popupContext[@"window"][@"opener"] = openerContext[@"window"];
        }
    
    
      //this is the secret sauce  
      if (webView == self.popUp
                && [webView.request.URL.absoluteString containsString:@"m.facebook.com"]
                && [[webView stringByEvaluatingJavaScriptFromString:@"document.body.innerHTML"] isEqualToString:@""]) {
            [webView stringByEvaluatingJavaScriptFromString:@"eval(document.getElementsByTagName('script')[0].text)"];
        }
    }
    

    I snagged a bunch of this implementation from here.

    Depending on your web implementation, there will likely be one extra step. The Facebook script actually executes a window.close() then a window.open() then a window.close(). For me this was causing problems because on the web side, after this login is complete, my window (i.e. for the webView that I want the user to log in to) was getting a window.close() call, coming from the Facebook SDK. I'm assuming this is because the Facebook SDK expects that window.open() call to open a new window that it will close.

    Since we didn't override the functionality of window.open(), calling window.open() won't do anything, and the Facebook SDK will attempt to close your window. This could cause all kind of problems, but for me since I'm using Parse, window.localStorage was set to null so I was getting all kinds of errors.

    If something like this is happening for you, you have two options to fix it:

    1. If you have control of the web code, and your down for a small hack, throw this in window.close=function(){}
    2. If you don't have control of the web code, you can either add an override to window.close for the main webView like we did for the popUp webView, or override the window.open function to open another popUp (which is described in more detail here)
    0 讨论(0)
提交回复
热议问题