UIWebView中的Facebook身份validation不会重定向回我站点上的原始页面,要求进行身份validation

在我们的iOS应用程序中,我们有一个UIWebView,显示我们域上具有Facebook评论模块的Web内容。 评论模块要求用户使用Facebook登录。 当用户点击登录按钮时,他们将通过登录流程,但永远不会重定向回我们的页面。 他们最终在FB拥有的页面上告诉用户“你现在已登录”。

Repro步骤:

  1. 在iOS应用程序中创建UIWebView,并在您拥有的某个域上托管的页面上托管Facebook评论模块(例如http://foo.com/test.htm )。
  2. 单击注释模块上的“登录”按钮,注意您将重定向到FB登录。
  3. 使用有效的FB凭证登录并观察会发生什么。

登录后(步骤3)我希望在成功validation后,您将被重定向回原始页面(例如http://foo.com/test.htm ),以便继续进行交互。 但是,这种情况并没有发生。

相反,你是一个FB拥有的页面,只是说“你现在已登录”,你被困在那里。 没有重定向发生。

这确实是一个错误还是我应该做些什么来确保重定向发生?

如果您只是支持iOS 8及更高版本,您可以使用已经实现@kabuko描述的function的WKWebView :

 // Container view including the main WKWebView var container : UIView? var popupWebView : WKWebView? override func viewDidLoad() { super.viewDidLoad() let prefs = WKPreferences() prefs.javaScriptEnabled = true // allow facebook to open the login popup prefs.javaScriptCanOpenWindowsAutomatically = true let config = WKWebViewConfiguration() config.preferences = prefs webView = WKWebView(frame: container.frame, configuration: config) webView?.UIDelegate = self webView?.navigationDelegate = self } // callback if the content of the webView wants to create a new window func webView(webView: WKWebView, createWebViewWithConfiguration configuration: WKWebViewConfiguration, forNavigationAction navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? { // create new popup webview and add it to the view hierarchy popupWebView = WKWebView(frame: container.frame, configuration: configuration) container.addSubview(popupWebView!) return popupWebView } func webView(webView: WKWebView, didFinishNavigation navigation: WKNavigation!) { // if the main webView loads a new page (eg due to succesful facebook login) // remove the popup if (popupWebView != nil) { popupWebView?.removeFromSuperview() popupWebView = nil } } 

我已经看到类似的事情发生在其他网站的FB登录(例如Groupon),如果你在UIWebView加载它们。 如果这是同样的问题(我认为是这样),那因为Facebook打开了你怀疑的弹出窗口中的登录窗口。 在普通浏览器上发生的事情是打开另一个窗口(弹出窗口)进行登录,然后当用户登录时,该登录窗口会回传到原始窗口,说它已登录。他们可能使用EasyXDM或类似的东西。 似乎有几层沟通策略,包括Flash和postMessage

在iOS(和Android)上,这应该意味着它最终会与postMessage通信。 如果您跟踪通过UIWebView的URL,您应该在最后看到类似的内容:

 https://s-static.ak.fbcdn.net/connect/xd_proxy.php#&relation=opener&transport=postmessage& 

UIWebView不支持多个窗口,因此不能将postMessage返回到原始页面,因为它已不再加载。 您可以做的是检测UIWebView何时尝试加载FB登录页面并将其加载到单独的UIWebView 。 现在你有两个窗口可以使用。

不幸的是,这仍然不够,因为FB页面上的JavaScript试图运行window.opener.postMessagewindow.parent.postMessage它不起作用,因为window.parentwindow.opener没有设置到适当的窗口。 我不知道在iOS中这样做的好方法(相比之下,Android为此提供了适当的API)。

我解决这个问题的方法是破解一个JavaScript对象来包装这些调用。 就像是:

 window.opener={}; window.opener.postMessage = function(data,url) { // signal your code in objective-c using some strategy }; window.parent = window.opener; 

有几种方法可以从JavaScript调用Objective-C,包括官方文档中的这个 。 您可以将此代码注入我之前提到的使用stringByEvaluatingJavaScriptFromString:静态FB登录页面stringByEvaluatingJavaScriptFromString: 。 我找不到这么做的好时机,所以我只是在页面加载后注入并调用doFragmentSend() ,这是通常在正文加载时调用的静态页面上的FB JavaScript方法。

所以现在我们需要做的就是通过调用postMessage将这些数据传递到原始的UIWebView 。 它看起来像这样:

 NSString *post = [NSString stringWithFormat:@"window.postMessage('%@', '*');", data]; [webView stringByEvaluatingJavaScriptFromString:post]; 

如果你现在还没有注意到,这是一个非常混乱的黑客,我可能不会推荐它,除非你别无选择,但它对我有用。

我有同样的问题。 我想,在Facebook登录后,UIWebView组件为空,其中没有html代码。 我通过检查webViewDidFinishLoad函数上的UIWebView组件的内容解决了这个问题,并在我检测到Facebook登录导致白色(空屏幕)时重新加载其内容:

 - (void)webViewDidFinishLoad:(UIWebView *)webView { if ( [[webView1 stringByEvaluatingJavaScriptFromString: @"document.body.innerHTML"] isEqualToString:@""] ) { [webView1 loadRequest:request]; //Define request as you want } } 

目前在移动设备中,浏览器默认不支持多个窗口。 另一种解决方案是监控来自facebook的成功重定向,如“close_popup.php?reload = https://”并重新加载页面。 还要确保在登录请求之前保留facebook注释值,以便可以将其再次放入注释框中。