为什么WKWebView无法打开target =“ _ blank”的链接?


122

WKWebView 不会打开任何包含 target="_blank"在其HTML <a href>标签中 “在新窗口中打开”属性的。


请更新标记为正确的答案
Efren

Answers:


184

我的解决方案是取消导航,并再次使用loadRequest:加载请求。这将是类似于UIWebView的行为,该行为始终在当前框架中打开新窗口。

实现WKUIDelegate委托并将其设置为_webview.uiDelegate。然后执行:

- (WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures
{
  if (!navigationAction.targetFrame.isMainFrame) {
    [webView loadRequest:navigationAction.request];
  }

  return nil;
}

4
这是正确的答案。我们尝试了接受的答案,但没有成功。但是@Cloud的答案有效,并且在开发论坛上的此答复解释了原因。
Christopher Pickslay 2014年

5
这个解决方案对我有用。不要忘记设置UIDelegate属性,因为此方法在WKUIDelegatenot中声明WKNavigationDelegate
佐藤武雄(Taketo Sano)

1
好的,我看到人们想像这样使用WKWebView。我实现了在我的项目github.com/sticksen/STKWebKitViewController中的同一WKWebView中打开target = _blank-Links的可能性(如上所示)。
stk

5
@ChristopherPickslay与我的WKWebView一起使用此方法时,请求url始终为空白,因此webview指向空白白页,有什么想法吗?
杰森·默里

1
当从带有帖子数据的表单发送“ _blank”请求时,我发现帖子数据将丢失!!!有什么帮助吗?@Cloud Wu
安德鲁

66

@Cloud Xu的答案是正确的答案。仅供参考,在Swift中:

// this handles target=_blank links by opening them in the same view
func webView(webView: WKWebView!, createWebViewWithConfiguration configuration: WKWebViewConfiguration!, forNavigationAction navigationAction: WKNavigationAction!, windowFeatures: WKWindowFeatures!) -> WKWebView! {
    if navigationAction.targetFrame == nil {
        webView.loadRequest(navigationAction.request)
    }
    return nil
}

2
如果要改为在Safari中打开它,您将如何编写?另外,我需要在视图控制器中引用什么才能使其正常工作?
2015年

1
要在移动浏览器中打开新页面,请参见以下答案:stackoverflow.com/a/30604481/558789
Paul Bruneau

1
这适用于链接,但似乎无法检测到使用JavaScript打开的新窗口,即window.open(url,“ _blank”)
Crashalot

FYI webView.loadRequest在API的最新版本中似乎已重命名为webView.load
Bill Weinman

52

使用最新版本的Swift 4.2+

import WebKit

使用WKUIDelegate扩展课程

为webview设置委托

self.webView.uiDelegate = self

实施协议方法

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

不是真正的重复。在您链接到的答案中,参数的可选性存在差异,这些差异与Swift 4.1 WKUIDelegate协议不一致。
yakattack

嗨,当我用Pinterest URL加载WKWebview时,无法打开“ Continue with Facebook”。现在,我可以单击并获取“ Continuew with Google”上的信息。请帮帮我。
NRV

我与wkwebview面临同样的问题;登录和重定向在我的应用中不起作用。有帮助吗?
Jamshed Alam

1
请任何人都可以帮帮我,我已将uiDelegate委托分配给wkwebview,但未调用使用配置创建Web视图的方法
chetan panchal

25

将您自己添加为WKNavigationDelegate

_webView.navigationDelegate = self;

并在委托回调DecisionPolicyForNavigationAction:decisionHandler中实现以下代码

- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler
{
    //this is a 'new window action' (aka target="_blank") > open this URL externally. If we´re doing nothing here, WKWebView will also just do nothing. Maybe this will change in a later stage of the iOS 8 Beta
    if (!navigationAction.targetFrame) { 
        NSURL *url = navigationAction.request.URL;
        UIApplication *app = [UIApplication sharedApplication];
        if ([app canOpenURL:url]) {
            [app openURL:url];
        }
    }
    decisionHandler(WKNavigationActionPolicyAllow);
}

PS:这段代码来自我的小项目STKWebKitViewController,它在WKWebView周围包装了一个可用的UI。


1
有错别字。WKNavigationActionPolicy和允许之间缺少一个点

@stk如何理解UIApplication是否要在Safari应用程序中打开链接?如果是苹果商店的链接-我需要在应用商店应用开OT,但如果是平常的网页-我需要在同一WKWebView打开stackoverflow.com/questions/29056854/...
BergP

1
@LeoKoppelkamm不是错字,而是Objective-C而不是Swift。;)
Ayan Sengupta

1
这适用于链接,但似乎无法检测到使用JavaScript打开的新窗口,即window.open(url, "_blank")
Crashalot

@Crashalot您找到window.open的解决方案了吗?
山姆

14

如果您已经设置了WKWebView.navigationDelegate

WKWebView.navigationDelegate =自我;

您只需要实现:

- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler
{
    BOOL shouldLoad = [self shouldStartLoadWithRequest:navigationAction.request]; // check the url if necessary

    if (shouldLoad && navigationAction.targetFrame == nil) {
        // WKWebView ignores links that open in new window
        [webView loadRequest:navigationAction.request];
    }

    // always pass a policy to the decisionHandler
    decisionHandler(shouldLoad ? WKNavigationActionPolicyAllow : WKNavigationActionPolicyCancel);
}

这样,您无需实现WKUIDelegate方法。


1
这适用于链接,但似乎无法检测到使用JavaScript打开的新窗口,即window.open(url,“ _blank”)
Crashalot


8

这些解决方案都不适合我,我确实通过以下方式解决了该问题:

1)实施WKUIDelegate

@interface ViewController () <WKNavigationDelegate, WKUIDelegate>

2)设置wkWebview的UIDelegate委托

self.wkWebview.UIDelegate = self;

3)实现createWebViewWithConfiguration方法

- (WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures {

if (!navigationAction.targetFrame.isMainFrame) {
    [UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
    [[UIApplication sharedApplication] openURL:[navigationAction.request URL]];
}
return nil;  }

这样做时,我只是得到一个SIGABRT。没用
user2009449'7

8

Cloud xu的答案解决了我的问题。

如果有人需要等效的Swift(4.x / 5.0)版本,则为:

func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? {
    if let frame = navigationAction.targetFrame,
        frame.isMainFrame {
        return nil
    }
    // for _blank target or non-mainFrame target
    webView.load(navigationAction.request)
    return nil
}

当然,您必须先设置webView.uiDelegate


7

我确认Bill Weinman的Swift代码正确。但是需要指出的是,如果您像我一样不熟悉iOS,则还需要委派UIDelegate使其正常工作。

像这样:

self.webView?.UIDelegate = self

因此,您需要在三个地方进行更改。


输入您的代码,它是:self.webView.UIDelegate = self
Henrik Petterson

不知道这是否暗含,但要使此代码行在iOS 10中正常工作,您ViewController需要继承WKUIDelegate。即class ViewController: UIViewController, WKNavigationDelegate, WKScriptMessageHandler, WKUIDelegate
ltrainpr

4

您还可以推送另一个视图控制器,或打开一个新标签,等等:

func webView(webView: WKWebView, createWebViewWithConfiguration configuration: WKWebViewConfiguration, forNavigationAction navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? {
    var wv: WKWebView?

    if navigationAction.targetFrame == nil {
        if let vc = self.storyboard?.instantiateViewControllerWithIdentifier("ViewController")  as? ViewController {
            vc.url = navigationAction.request.URL
            vc.webConfig = configuration
            wv = vc.view as? WKWebView

            self.navigationController?.pushViewController(vc, animated: true)
        }
    }

    return wv
}

是否需要设置vc.url?我没有设置它,并且Web视图正在正确加载。另外,根据我的经验,我只会看到createWebViewWithConfigurationwhen navigationAction.targetFramenil。您能描述一个不正确的情况吗?
Mason G. Zhwiti 2015年

@ MasonG.Zhwiti去年秋天,我一直在积极地将WKWebViews用于一个项目,但是从那时起,他们并没有对它们做任何事情-因此,我真的无法回答您的问题。在我发布上述内容时,它确实有效。我无法了解它的工作原理,但无需设置vc.url。
David H

我认为它之所以有用,是因为您要返回创建的Web视图,然后(我猜)要求您创建的任何内容都需要使用Web视图来加载有问题的URL。
Mason G. Zhwiti,2015年

3

基于艾伦·黄的回答

细节

  • Xcode版本10.3(10G8),Swift 5

目标

  • 检测链接 target=“_blank”
  • push 如果当前控制器具有webView的View Controller navigationController
  • present 在所有其他情况下使用带有webView的View Controller

webView.uiDelegate = self

// .....

extension ViewController: WKUIDelegate {
    func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? {
        guard   navigationAction.targetFrame == nil,
                let url =  navigationAction.request.url else { return nil }
        let vc = ViewController(url: url, configuration: configuration)
        if let navigationController = navigationController {
            navigationController.pushViewController(vc, animated: false)
            return vc.webView
        }
        present(vc, animated: true, completion: nil)
        return nil
    }
}

完整样本

信息清单

添加您的Info.plist传输安全设置

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

ViewController

import UIKit
import WebKit

class ViewController: UIViewController {

    private lazy var url = URL(string: "https://www.w3schools.com/html/tryit.asp?filename=tryhtml_links_target")!
    private weak var webView: WKWebView!

    init (url: URL, configuration: WKWebViewConfiguration) {
        super.init(nibName: nil, bundle: nil)
        self.url = url
        navigationItem.title = ""
    }

    required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) }

    override func viewDidLoad() {
        super.viewDidLoad()
        initWebView()
        webView.loadPage(address: url)
    }

    private func initWebView() {
        let webView = WKWebView(frame: .zero, configuration: WKWebViewConfiguration())
        view.addSubview(webView)
        self.webView = webView
        webView.navigationDelegate = self
        webView.uiDelegate = self
        webView.translatesAutoresizingMaskIntoConstraints = false
        webView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor).isActive = true
        webView.rightAnchor.constraint(equalTo: view.safeAreaLayoutGuide.rightAnchor).isActive = true
        webView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor).isActive = true
        webView.leftAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leftAnchor).isActive = true
    }
}

extension ViewController: WKNavigationDelegate {
    func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
        guard let host = webView.url?.host else { return }
        navigationItem.title = host
    }
}

extension ViewController: WKUIDelegate {
    func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? {
        guard   navigationAction.targetFrame == nil,
                let url =  navigationAction.request.url else { return nil }
        let vc = ViewController(url: url, configuration: configuration)
        if let navigationController = navigationController {
            navigationController.pushViewController(vc, animated: false)
            return vc.webView
        }
        present(vc, animated: true, completion: nil)
        return nil
    }
}

extension WKWebView {
    func loadPage(address url: URL) { load(URLRequest(url: url)) }
    func loadPage(address urlString: String) {
        guard let url = URL(string: urlString) else { return }
        loadPage(address: url)
    }
}

故事板

版本1

在此处输入图片说明

版本2

在此处输入图片说明


嗨,使用Facebook登录后,如何以类似方式打开Facebook共享的共享窗口?我已经通过创建新的wkwebview登录,现在用户已登录。现在如何跟踪共享窗口?
Jamshed Alam

谢谢您,您的解决方案可以挽救我的生命:)
Samrat Pramanik

2

这对我有用:

-(WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures {

if (!navigationAction.targetFrame.isMainFrame) {


    WKWebView *newWebview = [[WKWebView alloc] initWithFrame:self.view.frame configuration:configuration];
    newWebview.UIDelegate = self;
    newWebview.navigationDelegate = self;
    [newWebview loadRequest:navigationAction.request];
    self.view = newWebview;

    return  newWebview;
}

return nil;
}

- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {

    decisionHandler(WKNavigationActionPolicyAllow);
}

- (void)webViewDidClose:(WKWebView *)webView {
    self.view = self.webView;
}

如您所见,我们要做的只是webView使用新的url 打开一个新的URL,并控制关闭的可能性,即使您需要一个响应second webview才能显示在第一个URL 上。


1

我遇到了一些仅使用无法解决的问题webView.load(navigationAction.request)。因此,我使用创建一个新的webView来完成它,并且工作正常。

//MARK:- WKUIDelegate
func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? {
    NSLog(#function)

    if navigationAction.targetFrame == nil {
        NSLog("=> Create a new webView")

        let webView = WKWebView(frame: self.view.bounds, configuration: configuration)
        webView.uiDelegate = self
        webView.navigationDelegate = self

        self.webView = webView

        return webView
    }
    return nil
}

0
**Use following function to create web view**

func initWebView(configuration: WKWebViewConfiguration) 
{
        let webView = WKWebView(frame: UIScreen.main.bounds, configuration: configuration)
        webView.uiDelegate = self
        webView.navigationDelegate = self
        view.addSubview(webView)
        self.webView = webView
    }

**In View Did Load:**

 if webView == nil { initWebView(configuration: WKWebViewConfiguration()) }
   webView?.load(url: url1)


**WKUIDelegate Method need to be implemented**

extension WebViewController: WKUIDelegate {

    func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? {
        // push new screen to the navigation controller when need to open url in another "tab"
        print("url:\(String(describing: navigationAction.request.url?.absoluteString))")
        if let url = navigationAction.request.url, navigationAction.targetFrame == nil {
            let viewController = WebViewController()
            viewController.initWebView(configuration: configuration)
            viewController.url1 = url
            DispatchQueue.main.async { [weak self] in
                self?.navigationController?.pushViewController(viewController, animated: true)
            }
            return viewController.webView
        }

        return nil
    }
}

extension WKWebView 

{
    func load(url: URL) { load(URLRequest(url: url)) }
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.