【问题标题】:Why is WKWebView not opening links with target="_blank"?为什么 WKWebView 不打开带有 target="_blank" 的链接?
【发布时间】:2014-11-01 00:17:40
【问题描述】:

WKWebView 不会打开任何在其 HTML <a href>-Tag 中具有 target="_blank" 又名“在新窗口中打开”属性的链接。

【问题讨论】:

  • 请更新标记的正确答案

标签: ios wkwebview


【解决方案1】:

我的解决方案是取消导航并再次使用 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;
}

【讨论】:

  • 这是正确答案。我们尝试了接受的答案,但没有成功。但@Cloud 的回答有效,this response on the dev forums 解释了原因。
  • 这个解决方案对我有用。不要忘记设置UIDelegate 属性,因为此方法是在WKUIDelegate 而非WKNavigationDelegate 中声明的。
  • 好的,我看到人们想像这样使用 WKWebView。我在我的项目github.com/sticksen/STKWebKitViewController 中实现了在同一个 WKWebView(如上所示)中打开 target=_blank-Links 的可能性。
  • @ChristopherPickslay 在我的 WKWebView 使用此方法时,请求 url 始终为空白,因此 webview 指向空白页面,有什么想法吗?
  • @Cloud 我们可以在 Swift 中得到这个吗?
【解决方案2】:

@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
}

【讨论】:

  • 如果你想让它在 Safari 中打开,你会怎么写?另外,我需要在视图控制器中引用什么才能使其正常工作?
  • 要在移动 safari 中打开新页面,请参阅此答案:stackoverflow.com/a/30604481/558789
  • 这适用于链接,但似乎无法检测到使用 JavaScript 打开的新窗口,即 window.open(url, "_blank")
  • 仅供参考 webView.loadRequest 在 API 的最新版本中显然已重命名为 webView.load
【解决方案3】:

使用最新版本的 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 协议的参数的可选性存在差异。
  • 嗨,当我使用 Pinterest URL 加载 WKWebview 时,我无法打开“继续使用 Facebook”。现在我可以单击并获取有关“Continuew with Google”的信息。请帮帮我。
  • 我面临与 wkwebview 相同的问题;登录和重定向在我的应用程序中不起作用。有什么帮助吗?
  • 请任何人都可以帮助我,我已将委托 uiDelegate 分配给 wkwebview,但它的方法 create web view with configuration 未被调用
【解决方案4】:

将自己添加为 WKNavigationDelegate

_webView.navigationDelegate = self;

并在委托回调中实现以下代码decidePolicyForNavigationAction: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);
}

P.S.:这段代码来自我的小项目STKWebKitViewController,它围绕 WKWebView 包装了一个可用的 UI。

【讨论】:

  • 有一个错字。 WKNavigationActionPolicy 和 Allow 之间缺少一个点
  • @stk 我如何知道 UIApplication 是否要在 Safari 应用程序中打开链接?如果是 Appstore 链接 - 我需要在 Appstore 应用中打开 ot,但如果是普通网页 - 我需要在同一个 WKWebView stackoverflow.com/questions/29056854/… 中打开它
  • @LeoKoppelkamm 这不是拼写错误,而是 Objective-C 而不是 Swift。 ;)
  • @Crashalot 你找到 window.open 的解决方案了吗?
【解决方案5】:

如果你已经设置了 WKWebView.navigationDelegate

WKWebView.navigationDelegate = self;

你只需要实现:

- (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 方法了。

【讨论】:

  • 这适用于链接,但似乎无法检测到使用 JavaScript 打开的新窗口,即 window.open(url, "_blank")
  • @Crashalot 你检查过这个答案吗? stackoverflow.com/questions/33190234/wkwebview-and-window-open
  • 谢谢。在 nativescript "webView" "CreateWebViewWith" 没有被调用,我不知道为什么,而是决定PolicyForNavigationAction 工作。
【解决方案6】:

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】:

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

    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。它不起作用。
    【解决方案8】:

    我确认 Bill Weinman 的 Swift 代码是正确的。但需要提到的是,如果您像我一样不熟悉 iOS 开发,您还需要委托 UIDelegate 才能工作。

    类似这样的:

    self.webView?.UIDelegate = self
    

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

    【讨论】:

    • 输入你的代码,它是:self.webView.UIDelegate = self
    • 不确定是否隐含,但为了让这行代码在 iOS 10 中工作,您的 ViewController 需要继承 WKUIDelegate。即class ViewController: UIViewController, WKNavigationDelegate, WKScriptMessageHandler, WKUIDelegate
    【解决方案9】:

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

    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 视图正在正确加载。另外,根据我的经验,当navigationAction.targetFramenil 时,我只看到createWebViewWithConfiguration 被调用。你能描述一个不正确的场景吗?
    • @MasonG.Zhwiti 去年秋天我在一个项目中积极使用 WKWebViews,但从那时起就没有对它们做过任何事情——所以我真的无法回答你的问题。在我发布上述内容时,它确实有效。如果不设置 vc.url,我无法理解它是如何工作的。
    • 我认为它可以在没有的情况下工作,因为您正在返回您创建的 Web 视图,然后(我猜)任何要求您创建的内容都会处理使用 Web 视图加载 URL问题。
    【解决方案10】:

    基于allen huang answer

    详情

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

    目标

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

    解决方案

    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

    添加 Info.plist 传输安全设置

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

    视图控制器

    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 登录,现在用户已登录。现在如何跟踪共享窗口?
    • 谢谢你,你的解决方案救了我的命:)
    【解决方案11】:

    这对我有用:

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

    如您所见,我们在这里所做的只是使用新的 url 打开一个新的webView 并控制关闭的可能性,就像您需要来自 second webview 的响应以显示在第一个。

    【讨论】:

      【解决方案12】:

      在 Mobile Safari 中打开 _blank 页面,如果您使用 Swift:

      webView.navigationDelegate = self
      

      并在 WKNavigationDelegate 中实现:

      func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
          if navigationAction.targetFrame == nil, let url = navigationAction.request.url {
              if UIApplication.shared.canOpenURL(url) {
                  UIApplication.shared.open(url, options: [:], completionHandler: nil)
              }
          }
          decisionHandler(WKNavigationActionPolicy.allow)
      }
      

      【讨论】:

        【解决方案13】:

        我遇到了一些仅使用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
        }
        

        【讨论】:

          【解决方案14】:
          **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)) }
          }
          

          【讨论】:

            【解决方案15】:

            使用此方法在网页视图中下载pdf

            func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView?

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2015-08-16
              • 1970-01-01
              • 1970-01-01
              • 2020-08-09
              • 1970-01-01
              • 1970-01-01
              • 2012-07-06
              • 1970-01-01
              相关资源
              最近更新 更多