与WKWebView的JavaScript同步本机通信 [英] JavaScript synchronous native communication to WKWebView

查看:169
本文介绍了与WKWebView的JavaScript同步本机通信的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

使用WKWebView可以在JavaScript和Swift / Obj-C本机代码之间进行同步通信吗?

Is synchronous communication between JavaScript and Swift/Obj-C native code possible using the WKWebView?

这些是我尝试过但失败的方法。

These are the approaches I have tried and have failed.

方法1:使用脚本处理程序

Approach 1: Using script handlers

WKWebView 接收JS消息的新方法是使用委托方法 userContentController:didReceiveScriptMessage:这是通过<$从JS调用的c $ c> window.webkit.messageHandlers.myMsgHandler.postMessage('生命的含义是什么,本机代码?')
这种方法的问题在于执行本机代理期间方法,JS执行没有被阻止,所以我们不能通过立即调用 webView.evaluateJavaScript(something = 42,completionHandler:nil)来返回值。

WKWebView's new way of receiving JS messages is by using the delegate method userContentController:didReceiveScriptMessage: which is invoked from JS by window.webkit.messageHandlers.myMsgHandler.postMessage('What's the meaning of life, native code?') The problem with this approach is that during execution of the native delegate method, JS execution is not blocked, so we can't return a value by immediately invoking webView.evaluateJavaScript("something = 42", completionHandler: nil).

示例(JavaScript)

var something;
function getSomething() {
    window.webkit.messageHandlers.myMsgHandler.postMessage("What's the meaning of life, native code?"); // Execution NOT blocking here :(
    return something;
}
getSomething();    // Returns undefined

示例(Swift)

func userContentController(userContentController: WKUserContentController, didReceiveScriptMessage message: WKScriptMessage) {
    webView.evaluateJavaScript("something = 42", completionHandler: nil)
}

方法2:使用自定义网址

Approach 2: Using a custom URL scheme

在JS中,使用重定向window.location =js:// webView?hello = world调用本机 WKNavigationDelegate 方法,可以提取URL查询参数。但是,与UIWebView 不同,委托方法不会阻止JS执行,因此立即调用 evaluateJavaScript 到将值传递回JS在这里也不起作用。

In JS, redirecting using window.location = "js://webView?hello=world" invokes the native WKNavigationDelegate methods, where the URL query parameters can be extracted. However, unlike the UIWebView, the delegate method is not blocking the JS execution, so immediately invoking evaluateJavaScript to pass a value back to the JS doesn't work here either.

示例(JavaScript)

var something;
function getSomething() {
    window.location = "js://webView?question=meaning" // Execution NOT blocking here either :(
    return something;
}
getSomething(); // Returns undefined

示例(Swift)

func webView(webView: WKWebView, decidePolicyForNavigationAction navigationAction: WKNavigationAction, decisionHandler decisionHandler: (WKNavigationActionPolicy) -> Void) {
    webView.evaluateJavaScript("something = 42", completionHandler: nil)
    decisionHandler(WKNavigationActionPolicy.Allow)
}

方法3:使用自定义网址方案和IFRAME

Approach 3: Using a custom URL scheme and an IFRAME

此方法仅在分配 window.location 的方式上有所不同。而不是直接指定它, src 属性使用空的$ code> iframe 。

This approach only differs in the way that window.location is assigned. Instead of assigning it directly, the src attribute of an empty iframe is used.

示例(JavaScript)

var something;
function getSomething() {
    var iframe = document.createElement("IFRAME");
    iframe.setAttribute("src", "js://webView?hello=world");
    document.documentElement.appendChild(iframe);  // Execution NOT blocking here either :(
    iframe.parentNode.removeChild(iframe);
    iframe = null;
    return something;
}
getSomething();

尽管如此,它也不是解决方案,它调用与方法2相同的本机方法,即不同步。

This nonetheless, is not a solution either, it invokes the same native method as Approach 2, which is not synchronous.

附录:如何使用旧的UIWebView实现此目的

Appendix: How to achieve this with the old UIWebView

示例(JavaScript)

var something;
function getSomething() {
    // window.location = "js://webView?question=meaning" // Execution is NOT blocking if you use this.

    // Execution IS BLOCKING if you use this.
    var iframe = document.createElement("IFRAME");
    iframe.setAttribute("src", "js://webView?question=meaning");
    document.documentElement.appendChild(iframe);
    iframe.parentNode.removeChild(iframe);
    iframe = null;

    return something;
}
getSomething();   // Returns 42

示例(Swift)

func webView(webView: UIWebView, shouldStartLoadWithRequest request: NSURLRequest, navigationType: UIWebViewNavigationType) -> Bool {
    webView.stringByEvaluatingJavaScriptFromString("something = 42")    
}


推荐答案

不,由于WKWebView的多进程架构,我不相信它是可能的。 WKWebView在与应用程序相同的进程中运行,但它与在自己的进程中运行的WebKit进行通信(介绍Modern WebKit API )。 JavaScript代码将在WebKit进程中运行。所以基本上你要求在两个不同的进程之间进行同步通信,这违背了他们的设计。

No I don't believe it is possible due to the multi-process architecture of WKWebView. WKWebView runs in the same process as your application but it communicates with WebKit which runs in its own process (Introducing the Modern WebKit API). The JavaScript code will be running in the WebKit process. So essentially you are asking to have synchronous communication between two different processes which goes against their design.

这篇关于与WKWebView的JavaScript同步本机通信的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆