'iOS14, WKWebView cannot open links with _blank target

I have WKWebView that I want to use to browse a certain web site.

However some links with target="_blank" are not always opening. From run to run, I get different results.

Any ideas will be highly appreciated.

Here is my code. the WebViewStore is used by a SwiftUI View, that's why it is ObservableObject.

public class WebViewStore: NSObject, ObservableObject {
    @Published public var navDelegate = WebViewNavDelegate();
    @Published public var uiDelegate = WebViewUIDelegate();
    @Published public var webView: WKWebView = WKWebView() {
        didSet {
            log.info("WebViewStore.webView new WebView !!!")
            setupObservers()
        }
    }

    override public init() {
        super.init();
        log.info("WebViewStore.init")

        let preferences = WKPreferences()
        preferences.javaScriptEnabled = true

        let configuration = WKWebViewConfiguration()
        configuration.websiteDataStore =  WKWebsiteDataStore.nonPersistent()
        configuration.preferences = preferences

        let webView = WKWebView(frame: CGRect.zero, configuration: configuration)
        webView.translatesAutoresizingMaskIntoConstraints = false
        webView.allowsLinkPreview = true
        webView.allowsBackForwardNavigationGestures = true
        webView.isUserInteractionEnabled = true

        webView.uiDelegate = uiDelegate;
        webView.navigationDelegate = navDelegate;
        self.webView = webView;
    }

This is the navDelegate this is called only for some of the links!

public class WebViewNavDelegate : NSObject, WKNavigationDelegate, ObservableObject {
    public func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
        log.info("WebViewUI.webView : 6 - decidePolicyFor" )
        isLoading = true;

        log.info("url: \(navigationAction.request.url!.absoluteString)")
        log.info("target: \(navigationAction.targetFrame?.description)")
            
        // This allows the navigation
        decisionHandler(.allow)
    }
}

Here is my uiDelegate. I expect this to be called when new view is required, I would load it in the original (the same).

Unfortunately this method is called only sometimes ...

public class WebViewUIDelegate : NSObject, WKUIDelegate {
    
    public func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? {
        log.info("WebViewUIDelegate.webView() (createWebViewWith)")
        
        log.info("url: \(navigationAction.request.url?.absoluteString)" )
        log.info("target: \(navigationAction.targetFrame)" )

        if navigationAction.targetFrame == nil {
            webView.load(navigationAction.request)
        }
        return nil
    }
}


Solution 1:[1]

At the moment of writing this, WKWebView has some "unknown" bug with parsing the _blank target attributes of href tag.

It seems that Safari works properly when the target is _self.

The idea is to replace all _blank values with _self.

func webView(webView: WKWebView, didFinishNavigation navigation: WKNavigation!) {
    let jsCode = "var allLinks = document.getElementsByTagName('a');if (allLinks) { var i;for (i=0; i<allLinks.length; i++) {var link = allLinks[i];var target = link.getAttribute('target');if (target && target == '_blank') {link.setAttribute('target','_self');} } }"
    webView.evaluateJavaScript(jsCode, completionHandler: nil)
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Deian