使用 JavaScriptCore 进行跨语言调用时,既可以在 Native 代码中执行 JavaScript 代码,也可以在 JavaScript 中调用 Native 方法。以下是详细的实现步骤和示例。
1. 在 Native 代码中执行 JavaScript 代码
使用 JavaScriptCore 框架,可以在 Swift 或 Objective-C 代码中执行 JavaScript 代码,并获取执行结果。
示例(Swift)
步骤 1: 导入 JavaScriptCore 框架
import JavaScriptCore
步骤 2: 创建 JSContext 对象
let jsContext = JSContext()
步骤 3: 执行 JavaScript 代码
jsContext?.evaluateScript("var a = 2 + 2")
if let result = jsContext?.evaluateScript("a") {
print("Result: \(result.toInt32())") // 输出: Result: 4
}
示例代码:
import JavaScriptCore
class ViewController: UIViewController {
var jsContext: JSContext!
override func viewDidLoad() {
super.viewDidLoad()
jsContext = JSContext()
// 在 JavaScript 中定义一个函数
jsContext.evaluateScript("""
function add(a, b) {
return a + b;
}
""")
// 在 Swift 中调用 JavaScript 函数
if let addFunction = jsContext.objectForKeyedSubscript("add") {
let result = addFunction.call(withArguments: [3, 4])
print("Result of add function: \(result?.toInt32() ?? 0)") // 输出: Result of add function: 7
}
}
}
2. 在 JavaScript 中调用 Native 方法
通过 JavaScriptCore,可以将 Native 方法暴露给 JavaScript,这样就可以在 JavaScript 中调用这些方法。
示例(Swift)
步骤 1: 定义 Native 方法
let logFunction: @convention(block) (String) -> Void = { message in
print("Log from JavaScript: \(message)")
}
步骤 2: 将 Native 方法添加到 JSContext
jsContext.setObject(logFunction, forKeyedSubscript: "log" as NSString)
步骤 3: 在 JavaScript 中调用 Native 方法
jsContext.evaluateScript("""
log('Hello from JavaScript');
""")
示例代码:
import JavaScriptCore
class ViewController: UIViewController {
var jsContext: JSContext!
override func viewDidLoad() {
super.viewDidLoad()
jsContext = JSContext()
// 定义一个 Native 方法
let logFunction: @convention(block) (String) -> Void = { message in
print("Log from JavaScript: \(message)")
}
jsContext.setObject(logFunction, forKeyedSubscript: "log" as NSString)
// 在 JavaScript 中调用 Native 方法
jsContext.evaluateScript("""
log('Hello from JavaScript');
""")
}
}
3. 完整示例:双向调用
完整代码示例:
import JavaScriptCore
class ViewController: UIViewController {
var jsContext: JSContext!
override func viewDidLoad() {
super.viewDidLoad()
jsContext = JSContext()
// 定义一个 Native 方法
let logFunction: @convention(block) (String) -> Void = { message in
print("Log from JavaScript: \(message)")
}
jsContext.setObject(logFunction, forKeyedSubscript: "log" as NSString)
// 在 JavaScript 中定义一个函数
jsContext.evaluateScript("""
function add(a, b) {
log('Adding ' + a + ' and ' + b);
return a + b;
}
""")
// 在 Swift 中调用 JavaScript 函数
if let addFunction = jsContext.objectForKeyedSubscript("add") {
let result = addFunction.call(withArguments: [3, 4])
print("Result of add function: \(result?.toInt32() ?? 0)") // 输出: Result of add function: 7
}
// 在 JavaScript 中调用 Native 方法
jsContext.evaluateScript("""
log('Hello from JavaScript');
""")
}
}
小结
通过 JavaScriptCore,可以在 Native 代码中执行 JavaScript 代码,并在 JavaScript 中调用 Native 方法,实现跨语言调用。这种双向通信机制使得混合应用程序可以充分利用 JavaScript 和 Native 各自的优势,提升应用的功能性和用户体验。
异步还是同步 ?这是一个问题
使用 JavaScriptCore 进行跨语言调用(在 Native 代码中直接执行 JavaScript 代码,在 JavaScript 中调用 Native 方法),是异步还是同步的 ?
使用 JavaScriptCore 进行跨语言调用时,通常情况下调用是同步的。这意味着在 Native 代码中直接执行 JavaScript 代码时,调用会阻塞直到 JavaScript 代码执行完成,并且可以立即获取结果。同样地,在 JavaScript 中调用 Native 方法时,也是同步执行的。
详细解释
Native 代码中执行 JavaScript 代码
在 iOS 的 Swift/Objective-C 代码中,可以通过 JSContext
来执行 JavaScript 代码。调用 JSContext.evaluateScript
方法时,代码会同步执行,并且在执行完成后立即返回结果。
示例代码:
import JavaScriptCore
class ViewController: UIViewController {
var jsContext: JSContext!
override func viewDidLoad() {
super.viewDidLoad()
jsContext = JSContext()
// 在 JavaScript 中定义一个函数
jsContext.evaluateScript("""
function add(a, b) {
return a + b;
}
""")
// 在 Swift 中调用 JavaScript 函数
if let addFunction = jsContext.objectForKeyedSubscript("add") {
let result = addFunction.call(withArguments: [3, 4])
print("Result of add function: \(result?.toInt32() ?? 0)")
}
}
}
在这个示例中,evaluateScript
和 call
方法都是同步的,执行 JavaScript 代码后立即返回结果。
JavaScript 中调用 Native 方法
通过 JavaScriptCore,可以在 JavaScript 中调用通过 JSContext 暴露的 Native 方法。这些调用同样是同步的,JavaScript 代码会等待 Native 方法执行完成,并获取结果。
示例代码:
import JavaScriptCore
class ViewController: UIViewController {
var jsContext: JSContext!
override func viewDidLoad() {
super.viewDidLoad()
jsContext = JSContext()
// 定义一个 Native 方法
let logFunction: @convention(block) (String) -> Void = { message in
print("Log from JavaScript: \(message)")
}
jsContext.setObject(logFunction, forKeyedSubscript: "log" as NSString)
// 在 JavaScript 中调用 Native 方法
jsContext.evaluateScript("""
log('Hello from JavaScript');
""")
}
}
在这个示例中,JavaScript 中调用 log
方法会同步执行,Native 代码会立即执行打印操作。
同步执行的优缺点
优点
-
简单直观:
- 同步调用方式更容易理解和调试,因为代码按照顺序执行,没有复杂的回调和异步逻辑。
-
立即获取结果:
- 调用完成后可以立即获取执行结果,无需等待异步回调,适用于需要立即处理结果的场景。
缺点
-
可能阻塞线程:
- 如果 JavaScript 代码或 Native 方法执行时间较长,可能会阻塞当前线程,影响应用的响应性。
-
影响性能:
- 在主线程上进行耗时的同步操作可能会导致 UI 卡顿和用户体验下降。
如何处理耗时操作
为了避免同步调用带来的阻塞和性能问题,可以将耗时操作放到后台线程中执行。
示例代码:
import JavaScriptCore
class ViewController: UIViewController {
var jsContext: JSContext!
override func viewDidLoad() {
super.viewDidLoad()
jsContext = JSContext()
// 定义一个耗时的 Native 方法
let heavyTaskFunction: @convention(block) () -> String = {
Thread.sleep(forTimeInterval: 2) // 模拟耗时操作
return "Heavy task completed"
}
jsContext.setObject(heavyTaskFunction, forKeyedSubscript: "heavyTask" as NSString)
// 在后台线程中执行 JavaScript 代码
DispatchQueue.global().async {
if let result = self.jsContext.evaluateScript("heavyTask()") {
print("Result of heavy task: \(result.toString() ?? "")")
}
}
}
}
在这个示例中,耗时操作被放到后台线程中执行,避免了阻塞主线程,确保了应用的响应性。
小结
使用 JavaScriptCore 进行跨语言调用时,调用通常是同步的。这种同步调用方式简单直观,可以立即获取结果,但可能会导致线程阻塞和性能问题。为了避免这些问题,可以将耗时操作放到后台线程中执行,确保应用的响应性和用户体验。