本篇是基于Swift4.0為大家介紹下WKWebView與JS的交互.
OC版本請?zhí)D(zhuǎn)OC WKWebView與JS交互.
1.WKWebView調(diào)用JS
WKWebView可以直接使用下放方法調(diào)用JS.
open func evaluateJavaScript(_ javaScriptString: String, completionHandler: ((Any?, Error?) -> Swift.Void)? = nil)
舉個例子.我們需要獲取,一段HTML標簽的內(nèi)容.
HTML標簽內(nèi)容如下:
<input style="display:none;" name="input" value='I am Input'/>
我們需要在網(wǎng)頁加載完成的時候進行獲取,那么我們首先服從WKNavigationDelegate
協(xié)議,并且設(shè)置代理.然后在如下代理方法中執(zhí)行JS方法.
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
/// wkWebView調(diào)用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進行相應(yīng)的錯誤處理.
2.JS調(diào)用Swift
當JS端想傳一些數(shù)據(jù)給Swift.那它們會調(diào)用下方方法來發(fā)送.
window.webkit.messageHandlers.<方法名>.postMessage(<數(shù)據(jù)>)
上方代碼在JS端寫會報錯,導致網(wǎng)頁后面業(yè)務(wù)不執(zhí)行.可使用try-catch
執(zhí)行.
try {
//使用此方法,會報錯,因此使用try-catch
window.webkit.messageHandlers.<方法名>.postMessage(<數(shù)據(jù)>);
} catch(error) {
console.log('WKWebView post message');
}
那么下面就要在Swift接收JS傳來的數(shù)據(jù)了.
我們可以在WKScriptMessageHandler
協(xié)議中的方法來檢測傳來的數(shù)據(jù).
首先要對WKWebView添加方法名檢測的方法.
wkWebView.configuration.userContentController.add(self, name: <方法名>)
此時的代理對象為
self
(控制器本身),會存在內(nèi)存泄露問題
然后服從WKScriptMessageHandler
協(xié)議,在它的協(xié)議方法中我們就可以檢測到傳來的數(shù)據(jù)啦.
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
print("傳來的數(shù)據(jù)為", message.body)
}
3.JS調(diào)用Swift - 內(nèi)存泄露
上方已經(jīng)講到,將WKScriptMessageHandler
設(shè)置為self
,會造成內(nèi)存泄露問題.運行一下上述方法,會發(fā)現(xiàn)WKWebView所在控制器不走deinit()
方法.
我們可以創(chuàng)建一個專門用于檢測傳來數(shù)據(jù)的代理轉(zhuǎn)接下.
代碼如下:
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
的代理,進行轉(zhuǎn)接.
使用時只需要將原本添加檢測方法中的self
,替換為WeakScriptMessageDelegate
的實例就行了.
wkWebView.configuration.userContentController.add(WeakScriptMessageDelegate.init(self), name: <方法名>)
現(xiàn)在解決了控制器的回收,那么我們的轉(zhuǎn)接代理同樣也要釋放.
在控制器的deinit()
方法將其釋放一下就OK啦.
deinit {
wkWebView.configuration.userContentController.removeScriptMessageHandler(forName: <方法名>)
print("WKWebViewController is deinit")
}