web-dev-qa-db-ja.com

UIWebViewでのFacebook認証は、認証を要求する私のサイトの元のページにリダイレクトされません

IOSアプリには、Facebookコメントモジュールを持つドメイン上のWebコンテンツを表示するUIWebViewがあります。コメントモジュールでは、ユーザーがFacebookでサインインしている必要があります。ユーザーがサインインボタンをクリックすると、サインインフローが実行されますが、ページにリダイレクトされることはありません。最終的には、ユーザーに「サインインしました」とだけ伝えるFB所有のページが表示されます。

再現手順:

  1. IOSアプリでUIWebViewを作成し、所有しているドメインでホストされているページでFacebookコメントモジュールをホストします(例: http://foo.com/test.htm )。
  2. コメントモジュールの[サインイン]ボタンをクリックすると、FBサインインにリダイレクトされます。
  3. 有効なFB資格情報を使用してサインインし、何が起こるかを観察します。

サインインした後(ステップ3)、認証が成功すると、元のページ(例: http://foo.com/test.htm )にリダイレクトされ、続行できるようになると思います。あなたの相互作用。しかし、これは起こっていません。

代わりに、「あなたは今サインインしています」のような何かを言うだけのFB所有のページにいて、そこに閉じ込められています。リダイレクトは発生しません。

これは確かにバグですか、それともリダイレクトが確実に行われるようにするために他にすべきことはありますか?

21
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と通信することになることを意味するはずです。 UIWebViewを通過するURLを追跡すると、最後に次のようなものが表示されます。

_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にロードすることです。これで、2つのウィンドウを操作できます。

残念ながら、FBのページのJavaScriptが_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;
_

JavaScriptからObjective-Cを呼び出す方法はいくつかあります。 これは公式ドキュメントからのものです_stringByEvaluatingJavaScriptFromString:_ を使用する前に、このコードを前述の静的FBログインページに挿入できます。これを行うのに適した時間を見つけることができなかったので、ページの読み込み後に挿入し、通常はボディの読み込み時に呼び出される静的ページのFB JavaScriptメソッドであるdoFragmentSend()を呼び出します。

したがって、必要なのは、UIWebViewを呼び出してこのデータを元のpostMessageに渡すことだけです。次のようになります。

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

今まで気づかなかった場合、これは非常に厄介なハックであり、他に方法がない限り、おそらくお勧めしませんが、私にとってはうまくいきました。

8
kabuko

私も同じ問題を抱えていました。 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
    }
}
5
szpetip

現在モバイルでは、ブラウザはデフォルトで複数のウィンドウをサポートしていません。別の解決策は、「close_popup.php?reload = https://」のようなFacebookからのリダイレクトの成功を監視し、ページをリロードすることです。また、ログインリクエストの前にFacebookのコメント値を保存して、コメントボックスに再度入力できるようにしてください。

0
yogesh kumar