JavaScriptCore console.log

Я собрал очень простую программу, которая использует 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;
}

Идея здесь в том, что последним значением считается Number, и это значение печатается. Это работает для действительного кода javascript, например

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

Однако, если код пытается выполнить console.log, программа segfaults. Есть ли функция журнала, доступная в АО, или мне нужно сворачивать самостоятельно?

Ответ 1

Вам нужно предоставить свой собственный консольный журнал, если вы используете фреймворк JavaScriptCore с Mac или IOS.

Вот код, который работал у меня (извините, это Objective-C, а не стандартный C в соответствии с вашим кодом выше):

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

Затем вы используете его из Javascript:

consoleLog("My debug message");

Обратите внимание, что я попытался определить версию vararg (log с несколькими параметрами), но я не мог заставить это работать правильно в рамках api.

Обратите внимание, что это решение использует функции, введенные с новым API Objective-C для JavaScriptCore.framework, представленного одновременно с IOS 7. Если вы ищете введение в этот хорошо интегрированный мост между Objective-C и Javascript, ознакомьтесь с вступительным словом сессии WWDC 2013 года "Интеграция JavaScript в родные приложения" в сети Apple developer: 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");

Ответ 2

Swift 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)!)

Swift 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");

Ответ 3

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)

Ответ 4

Вы можете отлаживать JS файл, прикрепленный к контексту в Safari.

Шаги:

1) Запустить Safari

2) В Safari включите меню "Разработка", перейдя в "Настройки" → "Дополнительно" → "Показать меню разработчика в строке меню"

3) Перейдите в меню "Разработка" → "Симулятор" или название вашего компьютера → выберите "Автоматически показать веб-инспектор для JSContexts" и "Автоматически приостановить подключение к JSContexts"

4) Повторно запустите проект, и Safari должен автоматически показать веб-инспектора