是否可以使用 WKWebView 在 JavaScript 和 Swift/Obj-C 本机代码之间进行同步通信?
这些是我尝试过但失败的方法。
方法 1:使用脚本处理程序
WKWebView
接收JS消息的新方式是使用userContentController:didReceiveScriptMessage:
从JS调用的委托方法,window.webkit.messageHandlers.myMsgHandler.postMessage('What's the meaning of life, native code?')
这种方法的问题是在执行原生委托方法的过程中,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
示例(斯威夫特)
func userContentController(userContentController: WKUserContentController, didReceiveScriptMessage message: WKScriptMessage) {
webView.evaluateJavaScript("something = 42", completionHandler: nil)
}
方法 2:使用自定义 URL 方案
在 JS 中,重定向 usingwindow.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
示例(斯威夫特)
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
分配方式上有所不同。不是直接分配它,而是使用src
空的属性iframe
。
示例(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
示例(斯威夫特)
func webView(webView: UIWebView, shouldStartLoadWithRequest request: NSURLRequest, navigationType: UIWebViewNavigationType) -> Bool {
webView.stringByEvaluatingJavaScriptFromString("something = 42")
}