如何使用iOS上的JavaScriptCore创建从JavaScript调用的C 回调

How do I create a C++ callback invoked from JavaScript using JavaScriptCore on iOS?

本文关键字:调用 JavaScript 回调 创建 何使用 iOS 上的 JavaScriptCore      更新时间:2023-10-16

我正在使用JavaScript Core来促进我正在进行的iOS项目C 和JavaScript之间的通信。以下工作可从C 调用JavaScript函数:

#include <JavaScriptCore/JavaScriptCore.h>
void myCPPFunction()
{
    JSGlobalContextRef globalContext = 
    JSGlobalContextCreateInGroup(JSContextGroupCreate(), nullptr);
    auto funcOutput = JSEvaluateScript(globalContext,
        JSStringCreateWithUTF8CString(("function test() { 
            return 'hi'; } test();", nullptr, nullptr, 1, nullptr);
    // funcOutput now contains a JSValue containing the 
    // return value of the function ('hi').
}

现在,我想从JavaScript调用C 功能。例如,如果我的C 函数定义如下:

double myCPPCallback(unsigned long x)
{
    // do stuff
}

如何从我使用JSEvaluateScript运行的JavaScript调用此C 代码?

最容易与jsobjectMakeFunction在callback上完成您可以为您声明的jsobjectCallasFunctionCallback提供的内容,然后调用您的C 函数。然后,您可以用JavaScript代码以JSobjectMakeFunction WithCallback中的名称来调用回调。

还要注意,您也许不应该使用...

之类的东西
JSGlobalContextRef globalContext =
                   JSGlobalContextCreateInGroup(JSContextGroupCreate(), nullptr);

...因为这样您泄漏了组(JSContextGroupCreate()的结果)。我尝试制作示例OSX代码(没有时间测试):

#include <iostream>
#include <JavaScriptCore/JavaScriptCore.h>
JSValueRef HelloCallback( JSContextRef ctx             
                        , JSObjectRef function         
                        , JSObjectRef thisObject       
                        , size_t argumentCount         
                        , const JSValueRef arguments[] 
                        , JSValueRef* exception)       
{
    // here do the C++ stuff
    std::cout << "Hello World" << std::endl;
    return JSValueMakeUndefined(ctx);
}
int main(int argc, const char * argv[]) 
{
    // bad raw opaque pointers TODO: manage with smart pointers 
    JSContextGroupRef group = JSContextGroupCreate();
    JSGlobalContextRef globalContext = JSGlobalContextCreateInGroup(group, nullptr);
    JSObjectRef globalObject = JSContextGetGlobalObject(globalContext);
    JSStringRef helloFunctionName = JSStringCreateWithUTF8CString("hello");
    // make function object
    JSObjectRef functionObject = JSObjectMakeFunctionWithCallback( globalContext
                                                         , helloFunctionName
                                                         , &HelloCallback);
    // set it as proprty of global object
    JSObjectSetProperty( globalContext
                       , globalObject
                       , helloFunctionName
                       , functionObject
                       , kJSPropertyAttributeNone
                       , nullptr );
    // make javascript
    JSStringRef statement = JSStringCreateWithUTF8CString("hello()");
    // evaluate it
    JSEvaluateScript( globalContext
                    , statement
                    , nullptr
                    , nullptr
                    , 1
                    , nullptr );
    // manual raw pointer management ... hopefully did not forget any
    JSGlobalContextRelease(globalContext);
    JSContextGroupRelease(group);
    JSStringRelease(helloFunctionName);
    JSStringRelease(statement);
    return 0;
}