简体   繁体   中英

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

I'm using JavaScript core to facilitate communication between C++ and JavaScript for an iOS project I'm working on. The following works to invoke a javascript function from C++:

#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').

}

Now, I want to invoke a C++ function from the JavaScript. For example, if I have a C++ function defined as follows:

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

How do I invoke this C++ code from the JavaScript I'm currently running with JSEvaluateScript ?

It is easiest to do with JSObjectMakeFunctionWithCallback to what you can provide JSObjectCallAsFunctionCallback declared by you that then calls your C++ functions. Then you can call the callback in JavaScript code by name that you gave to it in JSObjectMakeFunctionWithCallback.

Also note that you should not perhaps use the very thing like ...

JSGlobalContextRef globalContext =
                   JSGlobalContextCreateInGroup(JSContextGroupCreate(), nullptr);

... because that way you leak the group (result of JSContextGroupCreate() ). I try to fabricate example OSX code (no time to test it):

#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;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM