11

We are developing an application for iOS 8.0 and above. This application requires authentication (or that the user registers for it). On the website, we use html forms to register and login users. These forms are responsive. User can also click on the "Log me in with Facebook button" to log in with FB credentials. This button is implemented with FB's SDK for Javascript (v2.4)

As such, we do not want to implement native screen on our iOS application for registration and log, but we rather implemented a view controller with a WKWebView element to handle this browsing experience.

However, we have noted that, when users tap on the "Log me in with Facebook button", nothing happens. The typical pop-up that FB opens to ask a user for login and grant permissions never appears.

Here is how we are initializing the WKWebView:

class LoginViewController: UIViewController, WKNavigationDelegate, WKUIDelegate {
var webView: WKWebView
@IBOutlet weak var cancelButton: UIButton!

override func viewDidLoad() {
    super.viewDidLoad()

    view.addSubview(webView)
    webView.setTranslatesAutoresizingMaskIntoConstraints(false)
    let height = NSLayoutConstraint(item: webView, attribute: .Height, relatedBy: .Equal, toItem: view, attribute: .Height, multiplier: 1, constant: 0)
    let width = NSLayoutConstraint(item: webView, attribute: .Width, relatedBy: .Equal, toItem: view, attribute: .Width, multiplier: 1, constant: 0)
    view.addConstraints([height, width])

    loadDefaultUrl()
}

required init(coder aDecoder: NSCoder){
    let config = WKWebViewConfiguration()
    config.preferences.javaScriptCanOpenWindowsAutomatically = true
    self.webView = WKWebView(frame: CGRectZero, configuration: config)
    super.init(coder: aDecoder)
    webView.navigationDelegate = self
    webView.UIDelegate = self
}

Would appreciate any pointers on how to make the FB login button work within a WKWebView (or, if doable, within a UIWebView).

Dharmesh Dhorajiya
  • 3,975
  • 9
  • 28
  • 39
Luis Delgado
  • 3,466
  • 1
  • 28
  • 48
  • Perhaps it is related to [this](https://bugs.webkit.org/show_bug.cgi?id=140188#c5) and [this](http://stackoverflow.com/questions/26253133/cant-set-headers-on-my-wkwebview-post-request). I'm having problems with login in WKWebView. Just a theory. – jvoll Aug 19 '15 at 20:44
  • @jvoll: maybe. Anyway I ended up going with the native login button and native UI elements, which is exactly what I did not want to do... – Luis Delgado Aug 20 '15 at 11:18
  • I´m having the same problem, login button was working with old UIWebView, with WKWebView it´s not! – Daniel Jul 12 '16 at 22:48

4 Answers4

18

A little late to answer, but I ran across the same problem lately and couldn't find any satisfying answer.

I have a solution but with iOS 9.0 by implementing two methods of WKUIDelegate, which you already registered yourself as for your webView. The authentication flow with the Facebook JS library will first open a popup window allowing the user to input its credentials, allow the information transmission, etc. and then the window will close returning to the parent window.

In order to do allow that flow, you first need to intercept the call to open the popup with the following method:

func webView(webView: WKWebView, createWebViewWithConfiguration configuration: WKWebViewConfiguration, forNavigationAction navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? {
    // A nil targetFrame means a new window (from Apple's doc)
    if (navigationAction.targetFrame == nil) {
        // Let's create a new webview on the fly with the provided configuration, 
        // set us as the UI delegate and return the handle to the parent webview
        let popup = WKWebView(frame: self.view.frame, configuration: configuration)
        popup.UIDelegate = self
        self.view.addSubview(popup)
        return popup
    }
    return nil;
}

Now that this is done, the new request will automatically be loaded in the "popup" WKWebView that was just created. The next step is to make sure to close it once the flow is done. Since we registered self as the popup.UIDelegate, we can remove the view when it will be closed by the external authentication flow:

func webViewDidClose(webView: WKWebView) {
    // Popup window is closed, we remove it
    webView.removeFromSuperview()
}

I hope this helps.

bernyfox
  • 301
  • 2
  • 5
5

Great answer from bernyfox. It worked for me after days of searching for a solution.

Here is the objective-c version:

- (WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures
{
    if (navigationAction.targetFrame == nil) {
        WKWebView *popup = [[WKWebView alloc]initWithFrame:self.view.frame configuration:configuration];
        popup.UIDelegate = self;
        [self.view addSubview:popup];
        return popup;
    }
}

-(void) webViewDidClose:(WKWebView *)webView{
    // Popup window is closed, we remove it
    [webView removeFromSuperview];
}
Guy Lowe
  • 1,853
  • 1
  • 20
  • 35
5

This is caused by WKWebView blocking links with target=_blank. The solution is to capture that situation and instead load the link directly in the view like this>

func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? {
    if navigationAction.targetFrame?.isMainFrame == nil {
        webView.load(navigationAction.request)
    }
    return nil
}

Solution derived from here Why is WKWebView not opening links with target="_blank"

Josef Richter
  • 171
  • 1
  • 6
0

@bernyfox's answer in Objective-C:

- (WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures
{
    if (!navigationAction.targetFrame.isMainFrame) {
        //[webView loadRequest:navigationAction.request];
        WKWebView *popup = [[WKWebView alloc] initWithFrame:self.view.frame configuration:configuration];
        popup.UIDelegate = self;
        [self.view addSubview:popup];
        return popup;
    }
    return nil;
}

- (void) webViewDidClose:(WKWebView *)webView {
    [webView removeFromSuperview];
}
Mdlc
  • 6,388
  • 11
  • 48
  • 95