JavaScriptCore
JavaScriptCore
是苹果提供的用来实现 iOS 和 前端JS 之间的交互库。作用是方便 Swift 调用JS方法和 JS调用 Swift 方法。
JSContext
JSContext 是Apple 提供的 JS 环境,所有的JS 语言都可以使用 evaluateScript()
直接执行和编译。例如:
// 通过JSContext执行js代码
let context: JSContext = JSContext()
let result1: JSValue = context.evaluateScript("1 + 3")
print(result1) // 输出4
如果在 context
中定义了方法,可以通过 objectForKeyedSubscript()
获得方法对象,再执行方法。例如:
context.evaluateScript("function sum(param1, param2) { return param1 + param2; }")
// 通过js方法名调用方法
let result2 = context.evaluateScript("sum(num1, num2)")
print(result2 as AnyObject) // 输出30
// 通过下标来获取js方法并调用方法
let squareFunc = context.objectForKeyedSubscript("sum")
let result3 = squareFunc?.call(withArguments: [10, 20]).toString()
调试 JS 代码
JS 和 Swift 混编的情况下,调试代码会变得比较复杂,JavaScriptCore 提供了异常处理方法。如下:
jsContext.exceptionHandler = {(context, exception) in
if let exception = exception{
print(exception.toString())
}
}
这样在 JS 中存在的Bug就可以在Swift 中进行捕获了。
实例演示
首先,实例话WebView 来展示网页。实现WebView 的代理方法 webViewDidFinishLoad()
获取WebView 渲染网页之后 持有的 JSContext
对象。
self.jsContext = webView.value(forKeyPath: "documentView.webView.mainFrame.javaScriptContext") as! JSContext
Swift 调用 JS 方法
通过上述方法获得了 Context 对象之后,使用 objectForKeyedSubscript()
获得方法对象,进行调用。
JS 调用 Swift 方法
在 WebView 渲染完毕之后,需要给 JSContext 传递一个 继承了 JSExport 协议的对象,这个对象中实现了 JS 可以调用的所有方法。具体操作如下:
func webViewDidFinishLoad(_ webView: UIWebView) {
self.jsContext = webView.value(forKeyPath: "documentView.webView.mainFrame.javaScriptContext") as! JSContext
let model = SwiftJavaScriptModel() // 继承了 JSExport 协议
// 这一步是将SwiftJavaScriptModel模型注入到JS中,在JS就可以通过WebViewJavascriptBridge调用我们暴露的方法了。
self.jsContext.setObject(model, forKeyedSubscript: "WebViewJavascriptBridge" as NSCopying & NSObjectProtocol)
}
借此,在 JS 代码中就可以通过 WebViewJavascriptBridge 进行调用了。例如:
// 定义协议SwiftJavaScriptDelegate 该协议必须遵守JSExport协议
@objc protocol SwiftJavaScriptDelegate: JSExport {
// js调用App功能
func record(_ orderNo: String)
}
<div class="btn-block" onclick="WebViewJavascriptBridge.record('Hello World')">
js调用App的方法。
</div>
总结
这篇文章总结了如何使用 JavaScriptCore 来实现 iOS 和 JS 之间的相互调用。这对于一些想要节省成本,只使用一套H5来适配 iOS 和 Android 端的公司来说,是一个很便捷的工具。