我怎样才能得到一个UIWebView响应在iOS 5和iOS 6的OAuth请求打开Facebook

2019-07-03 17:21发布

我们有:
(1)与Facebook OAuth的功能(以下简称“FB网络应用程序”)的Facebook基于API的Web应用
(2) UIWebView的基于浏览器在iPad(“浏览器”)

我们的目标是打开Facebook登录页面登录到FB Web应用程序(1)在iPad上的基于UIWebView中的浏览器(2)内。

这里有几分相似的问题:
http://facebook.stackoverflow.com/questions/11337285/no-longer-able-to-login-to-ios-app-via-oauth-the-page-requested-was-not-found

然而,这一问题的问题发生在用户输入登录名和密码后进入Facebook的形式。 我们的问题是,我们不能在第一时间显示在Facebook的登录表单。 从“网络”的“本地/桌面”更改应用程序类型,在这个问题的建议,并没有帮助。

脚步:
1.本打开我们的网页(简单的HTML页面) UIWebView浏览器
2.点击“FB的Web应用程序”启动按钮在此页
3. JavaScript的的OnClick试图发起OAuth的,应打开了Facebook的登录屏幕登录到FB的Web应用程序

目前的结果(问题):
在iOS 5. +和iOS 6. +设备
- 我们的网页保持不变
- Facebook登录页面不显示(我们的网页仍然显示)
在iOS 4.3(按预期工作):
- Facebook登录页面是在同一个打开UIWebView浏览器的对象(取代我们的网页)

预期结果:
显示Facebook登录页面,用户可以输入Facebook登录和密码 -
- 如果在iPad上的Safari浏览器推出了iOS上的5 +和iOS 6 +作品。 Facebook登录页面在一个单独的标签打开(相比之下,在没有单独的选项卡UIWebView

问:我怎样才能得到UIWebView响应于iOS上的OAuth请求5+和iOS 6+打开Facebook登录页面?

更多的技术细节:

我们登录不同NSURLRequest从内场

-(BOOL)webView(UIWebView*)webView shouldStartLoadWithRequest(NSURLREquest*)request navigationType:…   

我们注意到了“正确”和“不正确”的行为日志中的一些差异。 这里是如何执行流帮我看一下:

首先,我按“FB Web App的”起动按钮来启动的OAuth,那么某些情况下,去

的iOS 4.3,“正确的”
请求www.facebook.com/dialog/oauth?...
请求fbwebapp.com
请求m.facebook.com/login.php?....
--here Facebook登录出现

的iOS 5.0,“incorrect1”
请求www.facebook.com/dialog/oauth?...
请求fbwebapp.com
请求m.facebook.com/login.php?...

然后,它可能是
--a很多m.facebook.com/login.php?...with的下一个...在参数
其次是sqlite的错误
--right现在我明白了“对不起,出事了”页面从Facebook(这是第一次在所有我遇到它)

的iOS 6.0“incorrect2”
请求www.facebook.com/dialog/oauth?...
请求fbwebapp.com

- (无效)web视图:(的UIWebView *)webView的didFailLoadWithError:(NSError *)错误被调用,错误代码-999

你可以看到,行为的确依赖于IOS版本。 但常见的情况是获得m.facebook.com/login.php .. URL的步骤发生的错误。 但是,这一切,我们可以检测到。

我们正在敲打我们的头抵住墙一整天寻找解决方案。 绝望。
你能帮助我们在打开Facebook登录页面UIWebView响应OAuth的?

Answer 1:

只需使用:此代码

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);     
     }];
}

//这里manager.loginBehavior = FBSDKLoginBehaviorWeb; 是所有你需要在打开的Facebook UIWebview



Answer 2:

做到了!

它有点黑客攻击,但Facebook的JS SDK登录在一个UIWebView在iOS 6中的最后作品。

如何才能做到? 它是一个纯JS + JS的Facebook SDK + UIWebView的代表处理功能的解决方案。

JS - 第一步)

登录按钮(以连接Facebook)调用此函数例如,将触发面部JS登录/ OAuth的对话框:

function loginWithFacebookClick(){

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

}

JS - 第二步)

添加authResponseChange听众每次用户加载网页(后FB.init())来捕捉用户的连接状态:

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
}
});

并与应用程序的UIWebView的委托功能,你可以处理程序的Facebook的OAuth回应

目标C - 第三步)将

- (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];
    }
}

}

所以,当“重定向”用户最后加载页面,第二步是要在Facebook登录对话框到处理器的用户操作。

如果我得到了这样的回答太快,请问我! 希望能帮助到你。



Answer 3:

如果有人在谷歌上搜索,这里是为我工作:

-(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)"];
    }
}

我钩住了一堆这种实现的从这里 。

根据您的网络的实施,将有可能是一个额外的步骤。 Facebook的脚本实际执行window.close()window.open()然后window.close() 。 对我来说这是造成问题,因为在网络侧,在此之后登录完成后,我的窗口(即,我希望用户登录到web视图)是获得一个window.close()调用,从Facebook的SDK来。 我假设这是因为Facebook的SDK预计window.open()调用打开一个新的窗口将关闭。

由于我们没有覆盖的功能window.open()调用window.open()不会做任何事情,而Facebook的SDK会尝试关闭窗口。 这可能会导致各种各样的问题,但对我来说,因为我使用的解析, window.localStorage设置为null ,所以我让所有类型的错误。

如果这样的事情发生了你,你有两种选择来解决它:

  1. 如果你的网页代码控制,和你的小黑客下来,扔在这个window.close=function(){}
  2. 如果你没有的网页代码控制,您可以添加替代到window.close像我们一样的弹出webView的主web视图,或者重写window.open函数打开另一个弹出(其描述这里更详细 )


Answer 4:

使用FBDialog类来提示用户登录。 这对成功登录,用户在任何一个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];

然后,让你的类坚持FBDialogDelegate协议,而这个功能添加到您的类:

-(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!



Answer 5:

如何Facebook登录在UIWebView的。

Objective-C的

使用taylorstine的答案 。 他救了我的一天。 谢谢taylorstine

但是我用斯威夫特3.所以我只是转换下面的代码从taylorstine的答案。

斯威夫特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)")

    }

}


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