WKWebView无法打开社交媒体登录弹窗

4
我在我的应用程序中有一个WKWebView。除了我展示的网站上有社交媒体登录按钮以外,一切都顺利运行。问题是,它们显示(或试图显示)一个弹出窗口,让您允许其访问您的社交媒体帐户。我已经进行了研究并尝试了一些方法,但似乎没有适合的方法。这是我尝试过的内容:
在viewDidLoad中,我尝试在init上启用Javascript:
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];

然而这对我没有帮助。然后我尝试使用委托并走这条路线。我尝试玩createWebViewWithConfiguration方法,但是这似乎有些过度了,因为我必须过滤出它们是否在登录URL,然后配置一个弹出窗口并显示它。然后这仍然不起作用。我还进来处理if not main frame逻辑,取消请求并在主视图中重新加载它,这是一个简单的一行修复,而这个问题正在膨胀成20多行。
这似乎是一个常见的问题,但我似乎找不到很多信息。有什么想法吗?
编辑-添加
在玩Armands答案后,我越来越接近了。这是我的createWebViewWithConfig方法,它只显示一个白色屏幕覆盖层。就好像我需要某些东西告诉新的弹出窗口加载内容。此外-我假设我可以将此模态窗口放置在当前的.m文件中,而不需要完全新的文件?
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;
}
5个回答

11

Swift 4 和 Swift 5

创建两个WKWebView实例

var webView : WKWebView!
var newWebviewPopupWindow: WKWebView?

现在实现这些方法

func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? {
        newWebviewPopupWindow = WKWebView(frame: view.bounds, configuration: configuration)
        newWebviewPopupWindow!.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        newWebviewPopupWindow!.navigationDelegate = self
        newWebviewPopupWindow!.uiDelegate = self
        view.addSubview(newWebviewPopupWindow!)
        return newWebviewPopupWindow!
    }

    func webViewDidClose(_ webView: WKWebView) {
        webView.removeFromSuperview()
        newWebviewPopupWindow = nil
    }

如果您的代码仍然无法运行,请确保在Info.plist文件中包含此字符串。

 <key>NSAppTransportSecurity</key>
    <dict>
        <key>NSAllowsArbitraryLoads</key>
        <true/>
    </dict>

5

Armands的回答是正确的,但还有很大的改进空间。

  • 如果您希望WebViews能够相互配合(例如通过window.opener),则重要的是返回新创建的WebView(而不是nil)
  • 如果您使用传递给create调用的配置,则共享进程池会自动发生
  • 在createWebViewWith调用中不需要额外的检查。(如果您想防止任意弹出窗口或创建特定的WebViewController类型,则仍应列出URL白名单。)

在主WebViewController中(其中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
}

您仍然希望在新实例的弹出窗口WebViewController中拥有关闭监听器(其中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)
}

谢谢,你的回答有帮助。 - KamyFC

5

这些登录按钮试图打开一个新的标签页,但 WKWebView 不支持。据我所知,只有一种方法可以解决这个问题。

首先添加 WKUIDelegate 方法:

-(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;
}

在模态WKWebView中添加以下内容:
-(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是为Facebook设计的。如果您需要支持多个社交网络,请在它们的URL中找到独特的内容。

为了使此功能正常工作,您需要在WKWebViews之间共享Cookies。要做到这一点,您必须使用共享的WKProcessPool进行初始化。我喜欢将其存储在AppDelegate中。

可以像这样创建WKWebView:

- (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];
}

在AppDelegate中进行懒加载:

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

感谢您的帮助。它比以往任何时候都更进一步了。我不再遇到503禁止错误了。现在我遇到的问题是,这段代码只在当前webView上显示一个白色窗口。我可以验证它是在上面的,因为我没有设置自动调整大小的掩码,当我旋转手机时,我可以看到下面的内容。我认为我的问题在createWebViewWithConfiguration方法上。由于该方法太长,我无法发布整个方法。我将更新我的原始问题以包含它。 - Justin Pfenning
经过长时间的研究、编程和抓头发,我决定在WKWebView之外的Safari上尝试它。你知道吗——那里不起作用。我正在努力解决应用程序中的服务器端错误。在该错误被纠正后,现在它可以工作了。非常感谢您的帮助。将您的答案标记为正确的。 - Justin Pfenning
太好了。我很高兴这能有所帮助。 - Armands L.
根据文档,当需要打开一个新窗口时,targetFramenil。因此这里的代码有效是因为 navigationAction.targetFramenil,这使得 .isMainFrame 等同于 NO。但实际上你应该测试 navigationAction.targetFrame == nil - DarkDust

1

Swift4/5片段 - 使用MyWebView: 扩展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
    }

0

添加以下处理程序,弹出窗口就可以正常加载了。

# 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);
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接