This is the sixth day of my participation in the November Gwen Challenge. See details: The Last Gwen Challenge 2021.

Window. open is a method to open js pages, essentially in order to support the direct opening of the page on PC, but the mobile terminal also supports this method, but the processing method does not let it play the role of the task of opening a new window, the page link opened through window.open is actually loaded in the current WebView. UIWebView supports this js command by default, but WKWebView does not.

Window. Open in UIWebView

As mentioned above, window.open under UIWebView functions similarly to the A TAB, but there are also differences:

They have in common: both can respond to click events, triggering a link load;

The difference is that the A tag requires a full load URL link; But window.open has two cases:

The most basic way to call window.open is:

window.open(URL)
Copy the code

The performance of mobile terminals varies greatly with different parameter URLS:

(1) If the URL is a URL with scheme, such as www.baidu.com, the response is to load www.baidu.com;

(2) If the URL does not have Scheme, the representation is to replace the path of the URL of the current page with the URL (one of the standard parts of the URL), and then load the replaced URL.

For example:

If the current page for www.baidu.com/index.html, the path is/index. The HTML. Now, if within the page call Windows open (‘ www.jd.com ‘), the ultimate load of the url is www.baidu.com/www.jd.com, so that the window. The open call on the mobile end must be careful. If you want to open a new link, you must have Scheme.

How does WKWebView support?

As mentioned earlier, WKWebView does not support this method by default and needs to be set. There are some misguided practices on the Internet, namely

- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^) (WKNavigationActionPolicy))decisionHandler
{
 
        if(navigationAction.targetFrame = = nil || || !navigationAction.targetFrame.isMainFrame)
        {
            [webView loadRequest:navigationAction.request];
        }
        decisionHandler(WKNavigationActionPolicyAllow);
}
Copy the code

Because in the window. Open the trigger navigationAction. Under the condition of loading targetFrame = = nil, so expect this way to solve, but this code in this callback is no purpose. In fact window.open does not trigger the above callbacks by default.

We first from the wkWebView property set up to try, found a property:

/ *! @abstract A Boolean value indicating whether JavaScript can open windows without user interaction. @discussion The default value is NO in iOS and YES in OS X. */
@property (nonatomic) BOOL javaScriptCanOpenWindowsAutomatically;
Copy the code

The explanation of the method is the most likely way to solve the problem. We set this property to YES. But……

Unresolved problem!!

Later, we analyzed the proxy method of WKWebview and found the following findings:

/ *! @abstract Creates a new web view. @param webView The web view invoking the delegate method. @param configuration The configuration to use when creating the new web view. @param navigationAction The navigation action causing the new web view to be created. @param windowFeatures Window features requested by the webpage. @result A new web view or nil. @discussion The web view returned must be created with the specified configuration. WebKit will load the request in the returned web view. If you do not implement this method, the web view will cancel the navigation. */
- (nullable WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures;
Copy the code

The WKUIDelegate proxy method creates a new WebView, similar to the window.open proxy method

- (WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures{
    if(navigationAction.targetFrame = = nil || !navigationAction.targetFrame.isMainFrame)
    {
        [webView loadRequest:navigationAction.request];
    }
    return nil;
}
Copy the code

So return nil means you don’t open a new Webview, you load the current webview, behaves like a UIWebview.

After implementing this method, the problem is solved!!