ios - para - plugin facebook wordpress
La autenticación de Facebook en un UIWebView no redirige a la página original en mi sitio que solicita autenticación (4)
Actualmente en el móvil, el navegador no soporta múltiples ventanas por defecto. La solución alternativa es monitorear la redirección exitosa desde Facebook como "close_popup.php? Reload = https: //" y volver a cargar la página. También asegúrese de conservar el valor de comentario de Facebook antes de la solicitud de inicio de sesión para que se pueda poner nuevamente en el cuadro de comentarios.
En nuestra aplicación para iOS, tenemos un UIWebView que muestra contenido web en nuestro dominio que tiene un módulo de comentarios de Facebook. El módulo de comentarios requiere que el usuario haya iniciado sesión con facebook. Cuando el usuario hace clic en el botón de inicio de sesión, pasa por el flujo de inicio de sesión, pero nunca se redirige a nuestra página. Terminan en una página de propiedad de FB que simplemente le dice al usuario "Ya has iniciado sesión".
Repro pasos:
- Cree un UIWebView en una aplicación de iOS y hospede un módulo de comentarios de Facebook en una página alojada en algún dominio que tenga (p. Ej., http://foo.com/test.htm ).
- Haga clic en el botón Iniciar sesión en el módulo de comentarios y observe que está redirigido al inicio de sesión de FB.
- Inicie sesión con credenciales FB válidas y observe lo que sucede.
Después de que inicie sesión (paso 3) esperaría que después de una autenticación exitosa, sea redirigido nuevamente a la página original (por ejemplo, http://foo.com/test.htm ) para que pueda continuar con su interacción. Sin embargo, esto no está sucediendo.
En su lugar, estás en una página propiedad de FB que solo dice algo como "Ya has iniciado sesión" y estás atrapado allí. No se produce ninguna redirección.
¿Es esto realmente un error o hay algo más que debería hacer para asegurarme de que ocurra la redirección?
He visto que ocurre algo similar con los inicios de sesión de FB de otros sitios (por ejemplo, Groupon) si los carga en un UIWebView
. Si este es el mismo problema (que creo que es), se debe a que Facebook abre la ventana de inicio de sesión en una ventana emergente como sospechaba. Lo que sucede en un navegador normal es que otra ventana (ventana emergente) se abre para iniciar sesión, y luego, cuando el usuario inicia sesión, esa ventana de inicio de sesión se comunica con la ventana original para decir que ha iniciado sesión. Probablemente utilicen EasyXDM o algo similar. . Parece que hay algunas capas de estrategias para comunicarse, incluyendo Flash y postMessage
.
En iOS (y Android), esto debería significar que terminará comunicándose con postMessage
. Si realiza un seguimiento de las URL que pasan por su UIWebView
, debería ver algo como esto cerca del final:
https://s-static.ak.fbcdn.net/connect/xd_proxy.php#<lots of stuff>&relation=opener&transport=postmessage&<lots more stuff>
UIWebView
no admite varias ventanas, por lo que no puede postMessage
un postMessage
a su página original ya que ya no está cargado. Lo que puede hacer es detectar cuándo el UIWebView
está intentando cargar la página de inicio de sesión de FB y cargarla en un UIWebView
separado. Ahora tienes dos ventanas para trabajar.
Desafortunadamente, esto no es suficiente, ya que cuando el JavaScript en la página de FB intenta ejecutar window.opener.postMessage
o window.parent.postMessage
no funciona porque window.parent
y window.opener
no están configurados en la ventana apropiada. No conozco una buena manera de hacer esto en iOS (en contraste, Android proporciona una API adecuada para esto).
La forma en que he resuelto esto es hackear un objeto JavaScript para envolver estas llamadas. Algo como:
window.opener={};
window.opener.postMessage = function(data,url) {
// signal your code in objective-c using some strategy
};
window.parent = window.opener;
Hay algunas formas en que puede llamar a Objective-C desde JavaScript, incluido este de los documentos oficiales . Puede insertar este código en esa página de inicio de sesión de FB estática que mencioné antes de usar stringByEvaluatingJavaScriptFromString:
No pude encontrar un buen momento para hacer esto, así que lo doFragmentSend()
después de cargar la página y llamo a doFragmentSend()
que es el método FB JavaScript en esa página estática a la que normalmente se llama en la carga del cuerpo.
Así que ahora todo lo que tenemos que hacer es pasar estos datos al UIWebView
original llamando a postMessage
. Se verá algo como esto:
NSString *post = [NSString stringWithFormat:@"window.postMessage(''%@'', ''*'');", data];
[webView stringByEvaluatingJavaScriptFromString:post];
Si no lo has notado ahora, este es un gran truco desordenado y probablemente no lo recomendaría a menos que no tengas otra alternativa, pero ha funcionado para mí.
Yo tuve el mismo problema. Me di cuenta, después de que el inicio de sesión en Facebook los componentes de UIWebView están vacíos, no hay ningún código html dentro. Resolví el problema al verificar el contenido del componente UIWebView en la función webViewDidFinishLoad y volver a cargar su contenido cuando detecto que el inicio de sesión en Facebook causa blanco (pantalla vacía):
- (void)webViewDidFinishLoad:(UIWebView *)webView {
if ( [[webView1 stringByEvaluatingJavaScriptFromString:
@"document.body.innerHTML"] isEqualToString:@""] ) {
[webView1 loadRequest:request]; //Define request as you want
}
}
Si solo es compatible con iOS 8 y superior, puede usar WKWebView
que ya implementa la funcionalidad descrita por @kabuko :
// 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 (e.g. due to succesful facebook login)
// remove the popup
if (popupWebView != nil) {
popupWebView?.removeFromSuperview()
popupWebView = nil
}
}