WKWebView won't open social media login popups

拟墨画扇 提交于 2019-12-24 00:10:49

问题


I have a WKWebView in my app. Everything is running smooth except the website I show has the social media logon buttons. The problem is, they display (or try to display) a popup where you allow it to have access to your social media account. I have researched this and tried a few things, but none seem to fit. Here is what I tried:

in viewDidLoad, I tried to enable Javascript on the init:

WKWebViewConfiguration *theConfiguration = [[WKWebViewConfiguration alloc] init];
WKPreferences *thePreferences = [[WKPreferences alloc] init];
thePreferences.javaScriptCanOpenWindowsAutomatically = YES;
thePreferences.javaScriptEnabled = YES;
theConfiguration.preferences = thePreferences;
self.wkWeb = [[WKWebView alloc] initWithFrame:screenRect configuration:theConfiguration];

However, this didn't help me. Then I tried to play with the delegates and go that route. I tried playing around with the createWebViewWithConfiguration method, but that seems like overkill because I had to filter out if they are at the login URL then configure a popup and display it. And then this still wasn't working. I also come in here for the if not main frame logic, cancel the request and reload it in the main view, and that is an easy one-line fix where as this was ballooning into 20+ lines.

This seems like a common problem, but I can't seem to find a lot of information out there. Any ideas?

EDIT - Addition

After playing around with Armands answer, I get closer. This is my createWebViewWithConfig method now, which just displays a white screen overlay. It's like I need something to tell the new popup to load the content. Also - I assume I can place this modal window in my current .m file and it doesn't need a completely new file?

NSURL *url = navigationAction.request.URL;
if(!navigationAction.targetFrame.isMainFrame && [url.absoluteString rangeOfString:@"initiate_"].location != NSNotFound) {
    //open new modal webview
    AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
    WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init];
    config.processPool = [appDelegate getSharedPool];

    self.popupLogin = [[WKWebView alloc] initWithFrame:self.wkWeb.bounds configuration:config];
    self.popupLogin.frame = CGRectMake(self.wkWeb.frame.origin.x,
                                       self.wkWeb.frame.origin.y,
                                       self.wkWeb.frame.size.width,
                                       self.wkWeb.frame.size.height);
    self.popupLogin.navigationDelegate = self;
    self.popupLogin.UIDelegate = self;
    [webView addSubview:self.popupLogin];
    [self.popupLogin loadRequest:navigationAction.request];
    return nil;
}

回答1:


Those login buttons tries to open a new tab, which is not supported by WKWebView. As far as I know, there's only one way to do this.

First add WKUIDelegate method:

-(WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures
{
    NSURL *url = navigationAction.request.URL;
    if (navigationAction.targetFrame == nil && [url.absoluteString rangeOfString:@"facebook.com/dialog"].location != NSNotFound) {
        //Open new modal WKWebView
    }
    return nil;
}

In the modal WKWebView add this:

-(void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler
{
    NSURL *url = navigationResponse.response.URL;
    if ([url.absoluteString rangeOfString:@"close_popup.php"].location != NSNotFound) {
        //Close viewController
    }
    decisionHandler(WKNavigationResponsePolicyAllow);
}

close_popup.php is for Facebook. If you need to support multiple social networks, find something unique in their URLs.

In order for this to work, you will have to share Cookies between WKWebViews. To do this you have to init them with shared WKProcessPool. I prefer to store it in AppDelegate.

WKWebView can be created like this:

- (void)createWebView
{
    AppDelegate *delegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
    WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init];
    config.processPool = delegate.webViewProcessPool;

    self.webView = [[WKWebView alloc] initWithFrame:self.view.bounds configuration:config];
    self.webView.UIDelegate = self;
    self.webView.navigationDelegate = self;
    [self.view addSubview:self.webView];
}

In AppDelegate just lazy load it:

-(id)webViewProcessPool
{
    if (!_webViewProcessPool) {
        _webViewProcessPool = [[WKProcessPool alloc] init];
    }
    return _webViewProcessPool;
}



回答2:


Armands' answer is on the right track but can be improved significantly.

  • It's important to return the newly created webview (and not nil) if you want the webviews to be able to work with each other (e.g., via window.opener)
  • Sharing the process pool happens automatically if you use the configuration passed in to the create call
  • You don't need the extra checks in the createWebViewWith call. (You should still whitelist URLs if you want to prevent arbitrary popup windows or create specific WebViewController types.)

In your main WebViewController (where webView.uiDelegate = self):

func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? {
    let webView = WKWebView.init(frame: .zero, configuration: configuration)

    //OPTIONAL: check navigationAction.request.url to see what site is being opened as a popup

    //TODO HERE: Launch new instance of your WebViewController (within a nav controller)
    //and pass it this newly created webView to be added as main subview

    return webView
}

You do still want to have the close listener in the new instance of your popup WebViewController (where webView.navigationDelegate = self):

func webView(_ webView: WKWebView, decidePolicyFor navigationResponse: WKNavigationResponse, decisionHandler: @escaping (WKNavigationResponsePolicy) -> Void) {
    if let url = navigationResponse.response.url, url.absoluteString.hasPrefix("https://example.com/something-unique-to-this-popup-when-it-closes") {
        dismiss(animated: true, completion: nil)
    }
    decisionHandler(.allow)
}



回答3:


Add the following handlers and the popup window loads fine.

# pragma mark WKUIDelegate
- (nullable WKWebView *)webView:(WKWebView *)webView
createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration
forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures
(WKWindowFeatures *)windowFeatures
{
if (navigationAction.targetFrame == nil) {
    _popupWebViewObject = [[WKWebView alloc] initWithFrame:webView.frame configuration:configuration];
    _popupWebViewObject.customUserAgent = webView.customUserAgent;
    _popupWebViewObject.UIDelegate = self;
    _popupWebViewObject.navigationDelegate = self;
    [self.window.contentView addSubview:_popupWebViewObject];
    _popupWebViewObject.configuration.preferences.javaScriptCanOpenWindowsAutomatically = YES;
    _popupWebViewObject.configuration.preferences.javaScriptEnabled = YES;
    _popupWebViewObject.configuration.preferences.plugInsEnabled = YES;
    [_popupWebViewObject loadRequest:[navigationAction.request copy]];
    return _popupWebViewObject;
}
return nil;
}

- (void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(WKNavigation *)navigation {
    NSLog(@"%s", __FUNCTION__);
    NSLog(@"%@ TOKEN : ",webView.URL.absoluteString.lowercaseString);
    [self dismissPopWindow:webView];
}
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {
    [self dismissPopWindow:webView];
    decisionHandler(WKNavigationActionPolicyAllow);
}



回答4:


Swift4/5 snippet - using MyWebView: extended WkWebView:

func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration,
             for navigationAction: WKNavigationAction,
             windowFeatures: WKWindowFeatures) -> WKWebView? {
    if navigationAction.targetFrame == nil {
        let newView = MyWebView.init(frame: webView.frame, configuration: configuration)

        newView.customUserAgent = webView.customUserAgent
        newView.navigationDelegate = self
        newView.uiDelegate = self

        self.view.addSubview(newView)
        newView.fit(newView.superview!)

        newView.configuration.preferences.javaScriptCanOpenWindowsAutomatically = true
        newView.configuration.preferences.javaScriptEnabled = true
        newView.configuration.preferences.plugInsEnabled = true
        newView.load(navigationAction.request)

        return newView
    }


来源:https://stackoverflow.com/questions/39070722/wkwebview-wont-open-social-media-login-popups

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!