使用WKWebView可以在JavaScript和Swift / Obj-C本机代码之间进行同步通信吗?
这些是我尝试过的并且失败的方法.
方法1:使用脚本处理程序
WKWebView接收JS消息的新方式是使用委托方法userContentController:didReceiveScriptMessage:从JS调用的是window.webkit.messageHandlers.myMsgHandler.postMessage(“生命的本机代码是什么意思?”)
这种方法的问题是在执行本机委托方法时,JS执行不被阻止,所以我们不能立即调用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:使用自定义URL方案
在JS中,使用window.location =“js:// webView?hello = world”进行重定向调用本机WKNavigationDelegate方法,可以提取URL查询参数.但是,与UIWebView不同,委托方法不阻止JS执行,因此立即调用evaluateJavaScript将值传回给JS也不起作用.
示例(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:使用自定义URL方案和IFRAME
这种方法仅在分配window.location的方式上有所不同.而不是直接分配它,而是使用空的iframe的src属性.
示例(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相同的本机方法,它不是同步的.
附录:如何用旧的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与您的应用程序运行在相同的过程中,但它会与运行在其自身进程(
Introducing the Modern WebKit API)的WebKit进行通信. JavaScript代码将在WebKit进程中运行.因此,基本上你要求在两个不同的进程之间进行同步通信,这违反了他们的设计.