本篇是基于Swift4.0为大家介绍下WKWebView与JS的交互.
OC版本请跳转OC WKWebView与JS交互.
1.WKWebView调用JS
WKWebView可以直接使用下放方法调用JS.
open func evaluateJavaScript(_ javaScriptString: String, completionHandler: ((Any?, Error?) -> Swift.Void)? = nil)
举个例子.我们需要获取,一段HTML标签的内容.
HTML标签内容如下:
<input style="display:none;" name="input" value='I am Input'/>
我们需要在网页加载完成的时候进行获取,那么我们首先服从WKNavigationDelegate
协议,并且设置代理.然后在如下代理方法中执行JS方法.
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
/// wkWebView调用js方法
let js = "document.getElementsByName('input')[0].attributes['value'].value"
wkWebView.evaluateJavaScript(js) { (response, error) in
print("response:", response ?? "No Response", "\n", "error:", error ?? "No Error")
}
}
通过以上操作就成功获取到input标签的value属性值了.如果报错,可以通过error进行相应的错误处理.
2.JS调用Swift
当JS端想传一些数据给Swift.那它们会调用下方方法来发送.
window.webkit.messageHandlers.<方法名>.postMessage(<数据>)
上方代码在JS端写会报错,导致网页后面业务不执行.可使用try-catch
执行.
try {
//使用此方法,会报错,因此使用try-catch
window.webkit.messageHandlers.<方法名>.postMessage(<数据>);
} catch(error) {
console.log('WKWebView post message');
}
那么下面就要在Swift接收JS传来的数据了.
我们可以在WKScriptMessageHandler
协议中的方法来检测传来的数据.
首先要对WKWebView添加方法名检测的方法.
wkWebView.configuration.userContentController.add(self, name: <方法名>)
此时的代理对象为
self
(控制器本身),会存在内存泄露问题
然后服从WKScriptMessageHandler
协议,在它的协议方法中我们就可以检测到传来的数据啦.
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
print("传来的数据为", message.body)
}
3.JS调用Swift - 内存泄露
上方已经讲到,将WKScriptMessageHandler
设置为self
,会造成内存泄露问题.运行一下上述方法,会发现WKWebView所在控制器不走deinit()
方法.
我们可以创建一个专门用于检测传来数据的代理转接下.
代码如下:
import UIKit
import WebKit
class WeakScriptMessageDelegate: NSObject, WKScriptMessageHandler {
weak var scriptDelegate: WKScriptMessageHandler?
init(_ scriptDelegate: WKScriptMessageHandler) {
self.scriptDelegate = scriptDelegate
super.init()
}
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
scriptDelegate?.userContentController(userContentController, didReceive: message)
}
deinit {
print("WeakScriptMessageDelegate is deinit")
}
}
将它作为WKScriptMessageHandler
的代理,进行转接.
使用时只需要将原本添加检测方法中的self
,替换为WeakScriptMessageDelegate
的实例就行了.
wkWebView.configuration.userContentController.add(WeakScriptMessageDelegate.init(self), name: <方法名>)
现在解决了控制器的回收,那么我们的转接代理同样也要释放.
在控制器的deinit()
方法将其释放一下就OK啦.
deinit {
wkWebView.configuration.userContentController.removeScriptMessageHandler(forName: <方法名>)
print("WKWebViewController is deinit")
}