pau*_*lvs 26 swift ios8 wkwebview
使用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
Run Code Online (Sandbox Code Playgroud)
示例(Swift)
func userContentController(userContentController: WKUserContentController, didReceiveScriptMessage message: WKScriptMessage) {
webView.evaluateJavaScript("something = 42", completionHandler: nil)
}
Run Code Online (Sandbox Code Playgroud)
方法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
Run Code Online (Sandbox Code Playgroud)
示例(Swift)
func webView(webView: WKWebView, decidePolicyForNavigationAction navigationAction: WKNavigationAction, decisionHandler decisionHandler: (WKNavigationActionPolicy) -> Void) {
webView.evaluateJavaScript("something = 42", completionHandler: nil)
decisionHandler(WKNavigationActionPolicy.Allow)
}
Run Code Online (Sandbox Code Playgroud)
方法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();
Run Code Online (Sandbox Code Playgroud)
尽管如此,它也不是解决方案,它调用与方法2相同的本机方法,方法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
Run Code Online (Sandbox Code Playgroud)
示例(Swift)
func webView(webView: UIWebView, shouldStartLoadWithRequest request: NSURLRequest, navigationType: UIWebViewNavigationType) -> Bool {
webView.stringByEvaluatingJavaScriptFromString("something = 42")
}
Run Code Online (Sandbox Code Playgroud)
不,由于WKWebView的多进程架构,我不相信它是可能的.WKWebView在与应用程序相同的进程中运行,但它与在自己的进程中运行的WebKit进行通信(介绍Modern WebKit API).JavaScript代码将在WebKit进程中运行.所以基本上你要求在两个不同的进程之间进行同步通信,这违背了他们的设计.
我发现了一种进行同步通信的技巧,但尚未尝试:https ://stackoverflow.com/a/49474323/2870783
编辑:基本上,您可以使用 JS Prompt() 将有效负载从 js 端传送到本机端。在原生WKWebView中,必须拦截提示调用并判断它是普通调用还是jsbridge调用。然后您可以将结果作为提示调用的回调返回。因为提示调用是以等待用户输入的方式实现的,所以您的 javascript 原生通信将是同步的。缺点是只能通过字符串进行通信。
| 归档时间: |
|
| 查看次数: |
15887 次 |
| 最近记录: |