WKWebView target=“_blank” link open new tab in saf

2020-07-09 08:39发布

问题:

I understand this question has been asked a lot and I think I have viewed every single post about this and I still cannot get this to work. I'm new to swift and I think that is inhibiting me from being able to adapt code snippets from other answers.

So here's my question:

I am using a WKWebView to view a website in my app. When I click on a link that opens a new tab nothing happens. I want that new tab to open in safari or at least in a new wkwebview. I've tried implementing this answer from: https://stackoverflow.com/a/27391215, and Open a WKWebview target="_blank" link in Safari and many other similar answers, but am making no progress. What do I need to do to make this work in swift 4?

Currently I just have this since I wasn't able to implement any of the other solutions I found successfully:

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

But it doesn't seem to do anything. If someone could help point me in the right direction I would really appreciate it.

回答1:

I have pasted some sample code of a WKWebView project (load local html from folder) that requires links that have target=_blank to open in a new browser window.

I have highlighted the 3 things you must have to get links to open correctly.

  1. class ViewController extends WKUIDelegate
  2. self.webView.uiDelegate = self
  3. Use UIApplication.shared.open instead of webView.load

Let me know it it works and if anyone can suggest improvements to the sample code below, that would help me too :)

Full sample code for Xcode 9.2, Swift 4 below.

Good Luck

import UIKit
import WebKit

class ViewController: UIViewController, WKNavigationDelegate, WKUIDelegate {

    @IBOutlet weak var webView: WKWebView!
    override func viewDidLoad() {
        super.viewDidLoad()
        self.webView.uiDelegate = self

        let htmlPath = Bundle.main.path(forResource: "index", ofType: "html", inDirectory: "www")
        let htmlUrl = URL(fileURLWithPath: htmlPath!)
        let htmlDir = Bundle.main.url(forResource: "www", withExtension: nil)
        webView.loadFileURL(htmlUrl, allowingReadAccessTo: htmlDir!)
    }

    func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? {
        if navigationAction.targetFrame == nil {
            //webView.load(navigationAction.request)
            UIApplication.shared.open(navigationAction.request.url!, options: [:])
        }
        return nil
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }

    override var prefersStatusBarHidden: Bool {
        return true
    }

}


回答2:

Details

  • Xcode 10.2 (10E125), Swift 5

Solution

extension ViewController: 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"
        if let url = navigationAction.request.url, navigationAction.targetFrame == nil {
            let viewController = ViewController()
            DispatchQueue.main.async { [weak self] in
                self?.navigationController?.pushViewController(viewController, animated: true)
            }
            // .....
            return viewController.webView
        }
        return nil
    }

Full sample

Info.plist

add in your Info.plist transport security setting

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

Code

import UIKit
import WebKit

class ViewController: UIViewController {

    private lazy var url = URL(string: "https://google.com")!
    private weak var webView: WKWebView?

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

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        if webView == nil { initWebView(configuration: WKWebViewConfiguration()) }
        webView?.load(url: url)
    }
}

extension ViewController: 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"
        if let url = navigationAction.request.url, navigationAction.targetFrame == nil {
            let viewController = ViewController()
            viewController.initWebView(configuration: configuration)
            viewController.url = 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)) }
}