it-swarm.com.ru

Аутентификация Facebook в UIWebView не перенаправляет обратно на исходную страницу моего сайта с просьбой авторизации

В нашем приложении для iOS у нас есть UIWebView, который показывает веб-контент в нашем домене с модулем комментариев Facebook. Модуль комментариев требует, чтобы пользователь вошел в Facebook. Когда пользователь нажимает кнопку входа, он проходит через вход, но никогда не перенаправляется обратно на нашу страницу. Они попадают на страницу, принадлежащую FB, которая просто сообщает пользователю "Вы вошли в систему".

Репро шаги

  1. Создайте UIWebView в приложении для iOS и разместите модуль комментариев Facebook на странице, размещенной в вашем домене (например, http://foo.com/test.htm ).
  2. Нажмите на кнопку "Войти" в модуле комментариев и обратите внимание, что вы перенаправлены на страницу входа в FB.
  3. Войдите с действительными учетными данными FB и посмотрите, что произойдет.

После входа в систему (шаг 3) я ожидаю, что после успешной аутентификации вы будете перенаправлены обратно на исходную страницу (например, http://foo.com/test.htm ), чтобы вы могли продолжить ваше взаимодействие Однако этого не происходит.

Вместо этого вы находитесь на странице, принадлежащей FB, которая просто говорит что-то вроде "Вы сейчас вошли в систему", и вы попали туда. Перенаправления не происходит.

Это действительно ошибка или есть что-то еще, что я должен сделать, чтобы обеспечить перенаправление?

20
TMC

Если вы просто поддерживаете iOS 8 и выше, вы можете использовать WKWebView , которая уже реализует функциональность, описанную @ 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
    }
}
10
dthulke

Я видел, что нечто подобное происходит с логинами FB других сайтов (например, Groupon), если вы загружаете их в UIWebView. Если это та же самая проблема (которая, я думаю, есть), то она из-за того, что Facebook открывает окно входа во всплывающем окне, как вы и предполагали. Что происходит в обычном браузере, так это то, что другое окно (всплывающее окно) открывается для входа в систему, а затем, когда пользователь входит в систему, это окно входа возвращается в исходное окно, чтобы сказать, что оно вошло в систему. Возможно, они используют EasyXDM или что-то подобное , Кажется, что есть несколько уровней стратегий для общения, включая Flash и postMessage.

На iOS (и Android) это должно означать, что в конечном итоге он будет общаться с postMessage. Если вы отслеживаете URL, которые проходят через ваше UIWebView, вы должны увидеть что-то вроде этого в конце:

https://s-static.ak.fbcdn.net/connect/xd_proxy.php#<lots of stuff>&relation=opener&transport=postmessage&<lots more stuff>

UIWebView не поддерживает несколько окон, поэтому не может postMessage вернуться на исходную страницу, поскольку она больше не загружается. Что вы можете сделать, это определить, когда UIWebView пытается загрузить страницу входа в FB и загрузить ее в отдельном UIWebView. Теперь у вас есть два окна для работы.

К сожалению, этого все еще недостаточно, так как когда JavaScript на странице FB пытается запустить window.opener.postMessage или window.parent.postMessage, он не работает, потому что window.parent и window.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;

Есть несколько способов вызвать Objective-C из JavaScript, включая это из официальных документов . Вы можете вставить этот код на страницу статического входа в FB, о которой я упоминал, прежде чем использовать stringByEvaluatingJavaScriptFromString: . Я не мог найти подходящее время для этого, поэтому я просто вставляю его после загрузки страницы и вызываю doFragmentSend(), который является методом FB JavaScript на той статической странице, которая обычно вызывается при загрузке тела.

Так что теперь все, что нам нужно сделать, это передать эти данные в исходное UIWebView, вызвав postMessage. Это будет выглядеть примерно так:

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

Если вы еще не заметили, это огромный грязный хак, и я, вероятно, не рекомендовал бы его, если у вас нет альтернативы, но это работает для меня.

8
kabuko

У меня такая же проблема. Я понял, что после входа в Facebook компоненты UIWebView пусты, в нем нет html-кода. Я решил проблему, проверив содержимое компонента UIWebView в функции webViewDidFinishLoad и перезагрузив его содержимое, когда я обнаружил, что вход в Facebook приводит к появлению белого (пустой экран):

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

В настоящее время в мобильном браузере по умолчанию не поддерживается несколько окон. Альтернативное решение состоит в том, чтобы отслеживать успешное перенаправление с Facebook, например "close_popup.php? Reload = https: //", и перезагружать страницу. Также убедитесь, что вы сохранили значение комментария facebook перед запросом входа в систему, чтобы его можно было снова поместить в поле для комментариев.

0
yogesh kumar