read

When using WKWebView (or UIWebView), we are actually using only 1 window.

For website that has Facebook login, it might open a new window (a popup) for the user to login. Once login is completed, this popup window will close, and it will use an obscure method to pass a message to the original window.

The message has a URL like the following:

https://m.facebook.com/v2.7/dialog/oauth?access_token=...&redirect_uri=...

Pitfall of 1 Window

The pitfall is that when we use WKWebView, by default, we have only 1 window.

A naive implementation to WKUIDelegate is usually to load a request in that same web view:

extension WebViewController: WKUIDelegate {
    // Handles when a new frame/window is to be opened
    func webView(webView: WKWebView, createWebViewWithConfiguration configuration: WKWebViewConfiguration, forNavigationAction navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? {
        webView.loadRequest(navigationAction.request)
        return nil
    }
}

When Facebook login wants to pass that message to the original window, it could NOT find that window, and so therefore it get stuck in the page (usually a white screen of nothing).

Handling Multiple Windows

The solution is to support multiple windows.

func webView(webView: WKWebView, createWebViewWithConfiguration configuration: WKWebViewConfiguration, forNavigationAction navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? {
    // nil means new window
    if navigationAction.targetFrame == nil {
        // A omit `createWebView`. It creates a new web view and add to your view.
        let newWebView = createWebView(withConfiguration: configuration)
        return newWebView
    }
    
    webView.loadRequest(navigationAction.request)
    return nil
}

I did not include what happens after this new web view is shown. For Facebook login case, you will probably want to remove the new web view in webView:didFinishNavigation:.

Edge Case: Error 999

In the code above, there is a weird scenario where some website will load https://m.facebook.com/v2.7/dialog/oauth?access_token=...&redirect_uri=... and result in didFailNavigation

A simple solution is to reload, after a few seconds.


Image

@samwize

¯\_(ツ)_/¯

Back to Home