JavaScriptCore
JavaScriptCore 是蘋果提供的用來實現(xiàn) iOS 和 前端JS 之間的交互庫。作用是方便 Swift 調(diào)用JS方法和 JS調(diào)用 Swift 方法。
JSContext
JSContext 是Apple 提供的 JS 環(huán)境,所有的JS 語言都可以使用 evaluateScript() 直接執(zhí)行和編譯。例如:
// 通過JSContext執(zhí)行js代碼
let context: JSContext = JSContext()
let result1: JSValue = context.evaluateScript("1 + 3")
print(result1) // 輸出4
如果在 context中定義了方法,可以通過 objectForKeyedSubscript() 獲得方法對象,再執(zhí)行方法。例如:
context.evaluateScript("function sum(param1, param2) { return param1 + param2; }")
// 通過js方法名調(diào)用方法
let result2 = context.evaluateScript("sum(num1, num2)")
print(result2 as AnyObject) // 輸出30
// 通過下標(biāo)來獲取js方法并調(diào)用方法
let squareFunc = context.objectForKeyedSubscript("sum")
let result3 = squareFunc?.call(withArguments: [10, 20]).toString()
調(diào)試 JS 代碼
JS 和 Swift 混編的情況下,調(diào)試代碼會變得比較復(fù)雜,JavaScriptCore 提供了異常處理方法。如下:
jsContext.exceptionHandler = {(context, exception) in
if let exception = exception{
print(exception.toString())
}
}
這樣在 JS 中存在的Bug就可以在Swift 中進(jìn)行捕獲了。
實例演示
首先,實例話WebView 來展示網(wǎng)頁。實現(xiàn)WebView 的代理方法 webViewDidFinishLoad() 獲取WebView 渲染網(wǎng)頁之后 持有的 JSContext 對象。
self.jsContext = webView.value(forKeyPath: "documentView.webView.mainFrame.javaScriptContext") as! JSContext
Swift 調(diào)用 JS 方法
通過上述方法獲得了 Context 對象之后,使用 objectForKeyedSubscript() 獲得方法對象,進(jìn)行調(diào)用。
JS 調(diào)用 Swift 方法
在 WebView 渲染完畢之后,需要給 JSContext 傳遞一個 繼承了 JSExport 協(xié)議的對象,這個對象中實現(xiàn)了 JS 可以調(diào)用的所有方法。具體操作如下:
func webViewDidFinishLoad(_ webView: UIWebView) {
self.jsContext = webView.value(forKeyPath: "documentView.webView.mainFrame.javaScriptContext") as! JSContext
let model = SwiftJavaScriptModel() // 繼承了 JSExport 協(xié)議
// 這一步是將SwiftJavaScriptModel模型注入到JS中,在JS就可以通過WebViewJavascriptBridge調(diào)用我們暴露的方法了。
self.jsContext.setObject(model, forKeyedSubscript: "WebViewJavascriptBridge" as NSCopying & NSObjectProtocol)
}
借此,在 JS 代碼中就可以通過 WebViewJavascriptBridge 進(jìn)行調(diào)用了。例如:
// 定義協(xié)議SwiftJavaScriptDelegate 該協(xié)議必須遵守JSExport協(xié)議
@objc protocol SwiftJavaScriptDelegate: JSExport {
// js調(diào)用App功能
func record(_ orderNo: String)
}
<div class="btn-block" onclick="WebViewJavascriptBridge.record('Hello World')">
js調(diào)用App的方法。
</div>
總結(jié)
這篇文章總結(jié)了如何使用 JavaScriptCore 來實現(xiàn) iOS 和 JS 之間的相互調(diào)用。這對于一些想要節(jié)省成本,只使用一套H5來適配 iOS 和 Android 端的公司來說,是一個很便捷的工具。