SwiftyJSCore

SwiftyJSCore 封装了 JavaScriptCore 框架,并提供了一种从 Swift 调用 JavaScript 函数的便捷方式。

SwiftyJSCore 支持:

注意

如果您的应用程序以 iOS 为目标,并且性能对您很重要,请考虑使用 WKWebView。WKWebView 在一个单独的进程中运行,没有安全问题,并使用 JIT 编译器,与 JavaScriptCore 相比,JS 速度明显更快。

示例

SwiftyJSCore 的 API 是并发的,将函数调用和 Promise 抽象为相同的异步 API。

JavaScript

var testString = () => {
    return "Foobar";
}
var testAsync = async (arg) => {
    return new Promise(resolve => resolve({ "id": arg.id, "name": "Test" }));
}
var testException = async () => {
    throw new TypeError("TestError");
}

Swift

let interpreter = try await JSInterpreter()
try await interpreter.evaluateFile(url: jsURL)
try await interpreter.eval("console.log(\"8+13=\", 8+13)")

try await interpreter.setObject(13, forKey: "thirteen")
let sum: Int = try await interpreter.eval("thirteen+8")
assert(sum == 21)

let string: String = try await interpreter.call(function: "testString")
assert(string == "Foobar")

您可以传递 Codable 实体和典型的 JavaScriptCore @objc/NSObject 类作为函数参数。返回值映射到 Swift 原始类型或 Codable 类型。

struct TestEntity: Codable {
    let id: Int
    let name: String
}

let entity: TestEntity = try await interpreter.call(
    function: "testAsync",
    arguments: [TestEntity(id: 123, name: "Foobar")])
assert(entity.id == 123 && entity.name == "Test")

do {
    let _: Int = try await interpreter.call(function: "testException")
} catch JSError.exception(let name, let message) {
    assert(name, "TypeError")
    assert(message, "TestError")
}

Swift 异步调用包装为 JavaScript Promise

在您的 JSExport 类中使用 wrapAsyncInJSPromise 将 Swift 异步函数导出到 JavaScript。

查看单元测试以获取使用 SwiftData 的示例。

JS

var fetchPostsForUser = async (id, db) => {
    const user = await db.fetchUser(id);
    return user.posts;
};

Swift

@objc protocol JSDatabaseAPIProtocol: JSExport {
    @objc func fetchUser(_ id: Int) -> JSValue
}

class JSDatabaseAPI: NSObject, JSDatabaseAPIProtocol {
    let db = DatabaseAPI()
    
    @objc func fetchUser(_ id: Int) -> JSValue {
        return wrapAsyncInJSPromise {
            return try await self.db.fetchUser(id: id)
        }
    }
}