26

我编写了一个非常简单的程序,它使用 JavaScriptCore 来评估 JS:

#import <CoreFoundation/CoreFoundation.h>
#import <JavaScriptCore/JavaScriptCore.h>

int main(int argc, const char * argv[])
{
    JSGlobalContextRef ctx = JSGlobalContextCreate(NULL);

    FILE *f = fopen(argv[1],"r");
    char * buffer = malloc(10000000);
    fread(buffer,1,10000000,f);

    CFStringRef strs = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingASCII);

    JSStringRef jsstr = JSStringCreateWithCFString(strs);
    JSValueRef result = JSEvaluateScript(ctx, jsstr, NULL, NULL, 0, NULL);

    double res  = JSValueToNumber(ctx, result, NULL);
    JSGlobalContextRelease(ctx);

    printf("%lf\n", res);
    return 0;
}

这里的想法是最后一个值应该是 a Number,并且该值被打印出来。这适用于有效的 javascript 代码,例如

var square = function(x) { return x*x; }; square(4)

但是,如果代码尝试执行 a console.log,则程序会出现段错误。JSC 中是否有可用的日志功能,还是我必须自己推出?

4

5 回答 5

24

如果使用 Mac 或 IOS 的 JavaScriptCore 框架,您必须提供自己的控制台日志。

这是一些对我有用的代码(抱歉,根据上面的代码,它是 Objective-C 而不是标准 C):

JSContext *javascriptContext  = [[JSContext alloc] init];
javascriptContext[@"consoleLog"] = ^(NSString *message) {
    NSLog(@"Javascript log: %@",message);
};

然后你通过 Javascript 使用它:

consoleLog("My debug message");

请注意,我试图定义一个可变参数版本(日志采用多个参数),但我无法让它在框架 api 中正常工作。

请注意,此解决方案使用新的 Objective-C API 引入的功能,用于与 IOS 7 同时引入的 JavaScriptCore.framework。如果您正在寻找有关 Objective-C 和 Javascript 之间良好集成桥梁的介绍,请查看Apple 开发者网络上的 2013 WWDC 介绍“将 JavaScript 集成到原生应用程序”会议:https ://developer.apple.com/videos/wwdc/2013/?id=615

更新回答:

对于那些想要在不重构的情况下最大限度地重用 javascript 代码的人,我已经设法获得了一个可以声明格式为console.log()的日志的版本:

JSContext *javascriptContext  = [[JSContext alloc] init];
[javascriptContext evaluateScript:@"var console = {}"];
javascriptContext[@"console"][@"log"] = ^(NSString *message) {
    NSLog(@"Javascript log: %@",message);
};

然后你通过 Javascript 使用它:

console.log("My debug message");
于 2014-01-24T05:39:49.427 回答
19

斯威夫特 3.0

let javascriptContext = JSContext()
javascriptContext?.evaluateScript("var console = { log: function(message) { _consoleLog(message) } }")
let consoleLog: @convention(block) (String) -> Void = { message in
    print("console.log: " + message)
}
javascriptContext?.setObject(unsafeBitCast(consoleLog, to: AnyObject.self), forKeyedSubscript: "_consoleLog" as (NSCopying & NSObjectProtocol)!)

斯威夫特 2.1

let javascriptContext = JSContext()
javascriptContext.evaluateScript("var console = { log: function(message) { _consoleLog(message) } }")
let consoleLog: @convention(block) String -> Void = { message in
    print("console.log: " + message)
}
javascriptContext.setObject(unsafeBitCast(consoleLog, AnyObject.self), forKeyedSubscript: "_consoleLog")

然后你通过 Javascript 使用它:

console.log("My debug message");
于 2016-03-08T21:06:04.840 回答
5
self.jsContext = JSContext()
self.jsContext.evaluateScript(...)       
let logFunction: @convention(block) (String) -> Void  = { (string: String) in
    print(string)
}

self.jsContext.setObject(logFunction, forKeyedSubscript: "consoleLog" as NSCopying & NSObjectProtocol)
于 2017-08-03T18:48:00.933 回答
3

您可以在 Safari 中调试附加到上下文的 JS 文件。

脚步:

1) 启动 Safari

2) 在 Safari 中,通过“首选项”->“高级”->“在菜单栏中显示开发菜单”启用开发菜单

3) 转到开发菜单->“模拟器”或您的计算机名称->选择“自动显示 JSContexts 的 Web 检查器”和“自动暂停连接到 JSContexts”

4) 重新运行您的项目,Safari 应该会自动显示网络检查器

于 2017-05-11T13:01:57.853 回答
1

斯威夫特 5.0

其他建议对我不起作用,所以我找到了一篇解释现在如何做的网络帖子。基本上

let logFunction: @convention(block) (String) -> Void = { string in
    print("JS_Console:", string)
}
if let console = context.objectForKeyedSubscript("console") {
    console.setObject(logFunction, forKeyedSubscript: "log") // works for me
    // is this needed? "console.setObject(unsafeBitCast(logFunction, to: AnyObject.self), forKeyedSubscript: "log")
}

log.console 是可变的,但即使上面的链接表明它是可能的,我也找不到使用它的方法。我确实发现您可以使用 JavaScript 插值来获取值,例如:

console.log(`getCombinedFrameYaw: ${frameYaw} rot=${pathRotation}`)
于 2022-02-25T18:11:43.983 回答