【问题标题】:How to use JSExport and JavascriptCore in C++如何在 C++ 中使用 JSExport 和 JavascriptCore
【发布时间】:2017-10-25 23:05:43
【问题描述】:

我在 C++ 项目中使用 JavascriptCore,但我不知道如何将 C++ 类公开给 javascript。例如在 Objective-C 中是这样的:

@protocol MyPointExports <JSExport>
@property double x;
@property double y;
- (NSString *)description;
- (instancetype)initWithX:(double)x y:(double)y;
+ (MyPoint *)makePointWithX:(double)x y:(double)y;
@end

@interface MyPoint : NSObject <MyPointExports>
- (void)myPrivateMethod;  // Not in the MyPointExports protocol, so not visible to JavaScript code.
@end

@implementation MyPoint
// ...
@end

JSContext *context = [[JSContext alloc] init];

// export MyPoint class
context[@"MyPoint"] = [MyPoint class];

但我不知道如何将 JSExport 和协议翻译成 C++。

【问题讨论】:

    标签: c++ javascriptcore


    【解决方案1】:

    看起来您需要使用 C API 来实现这一点。有关详细信息,请参阅this article。特别是“将原生对象定义为 JavaScript”部分。

    引用文章中的列表看起来与您想要实现的目标非常相似:

    #include <iostream>
    #include <JavaScriptCore/JavaScriptCore.h>
    #include <sys/stat.h>
    
    using namespace std;
    
    struct FilesystemPrivate {
        string path;
        bool is_directory;
        bool is_file;
        bool is_symlink;
        size_t size;
        bool exists;
    };
    
    std::string JSStringToStdString(JSStringRef jsString) {
        size_t maxBufferSize = JSStringGetMaximumUTF8CStringSize(jsString);
        char* utf8Buffer = new char[maxBufferSize];
        size_t bytesWritten = JSStringGetUTF8CString(jsString, utf8Buffer, maxBufferSize);
        std::string utf_string = std::string (utf8Buffer, bytesWritten -1); // the last byte is a null \0 which std::string doesn't need.
        delete [] utf8Buffer;
        return utf_string;
    }
    
    JSValueRef ObjectCallAsFunctionCallback(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) {
        for (size_t i=0; i<argumentCount; i++) {
            JSStringRef pathString = JSValueToStringCopy(ctx, arguments[i], nullptr);
            cout << JSStringToStdString(pathString);
        }
        cout << endl ;
        return JSValueMakeUndefined(ctx);
    }
    
    void setAttributes(FilesystemPrivate *fs, std::string path) {
        fs->path = path;
    
        struct stat statbuf;
    
        if (lstat(path.c_str(), &statbuf) != -1) {
            switch (statbuf.st_mode & S_IFMT){
                case S_IFREG:
                    fs->is_file = true;
                    break;
                case S_IFLNK:
                    fs->is_symlink = true;
                    break;
                case S_IFDIR:
                    fs->is_directory = true;
                    break;
            }
            fs->size = statbuf.st_size;
            fs->exists = true;
        }else{
            fs->exists = false;
            fs->is_file = false;
            fs->is_directory = false;
            fs->is_symlink = false;
            fs->size = 0;
        }
    }
    
    /* callbacks */
    
    void Filesystem_Finalize(JSObjectRef object){
        FilesystemPrivate *fs = static_cast<FilesystemPrivate*>(JSObjectGetPrivate(object));
        delete fs;
    }
    
    JSObjectRef Filesystem_CallAsConstructor(JSContextRef ctx, JSObjectRef constructor, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception){
        FilesystemPrivate *fs = new FilesystemPrivate();
    
        JSStringRef pathString = JSValueToStringCopy(ctx, arguments[0], nullptr);
        setAttributes(fs, JSStringToStdString(pathString));
        JSObjectSetPrivate(constructor, static_cast<void*>(fs));
    
        return constructor;
    }
    
    /* static values */
    
    JSValueRef Filesystem_getPath(JSContextRef ctx, JSObjectRef object,JSStringRef propertyName, JSValueRef* exception) {
        FilesystemPrivate *fs = static_cast<FilesystemPrivate*>(JSObjectGetPrivate(object));
        JSStringRef pathString = JSStringCreateWithUTF8CString(fs->path.c_str());
    
        return JSValueMakeString(ctx, pathString);
    }
    
    bool Filesystem_setPath(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef value, JSValueRef* exception) {
        FilesystemPrivate *fs = static_cast<FilesystemPrivate*>(JSObjectGetPrivate(object));
        JSStringRef pathString = JSValueToStringCopy(ctx, value, nullptr);
    
        setAttributes(fs, JSStringToStdString(pathString));
    
        return true;
    }
    
    JSValueRef Filesystem_getType(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception) {
        FilesystemPrivate *fs = static_cast<FilesystemPrivate*>(JSObjectGetPrivate(object));
        JSStringRef pathType;
    
        if (fs->is_file) {
            pathType = JSStringCreateWithUTF8CString("File");
        }else if (fs->is_directory) {
            pathType = JSStringCreateWithUTF8CString("Directory");
        }else if (fs->is_symlink) {
            pathType = JSStringCreateWithUTF8CString("Symlink");
        }else{
            pathType = JSStringCreateWithUTF8CString("Unknown");
        }
    
        return JSValueMakeString(ctx, pathType);
    }
    
    JSValueRef Filesystem_getExist(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception) {
        FilesystemPrivate *fs = static_cast<FilesystemPrivate*>(JSObjectGetPrivate(object));
    
        return JSValueMakeBoolean(ctx, fs->exists);
    }
    
    JSValueRef Filesystem_getSize(JSContextRef ctx, JSObjectRef object,JSStringRef propertyName, JSValueRef* exception) {
        FilesystemPrivate *fs = static_cast<FilesystemPrivate*>(JSObjectGetPrivate(object));
    
        return JSValueMakeNumber(ctx, static_cast<double>(fs->size));
    }
    
    JSValueRef Filesystem_remove(JSContextRef ctx, JSObjectRef function, JSObjectRef object, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception){
        FilesystemPrivate *fs = static_cast<FilesystemPrivate*>(JSObjectGetPrivate(object));
        remove(fs->path.c_str());
    
        return JSValueMakeUndefined(ctx);
    }
    
    JSClassRef FilesystemClass() {
        static JSClassRef filesystem_class;
        if (!filesystem_class) {
            JSClassDefinition classDefinition = kJSClassDefinitionEmpty;
    
            static JSStaticFunction staticFunctions[] = {
                { "remove", Filesystem_remove, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
                { 0, 0, 0 }
            };
    
            static JSStaticValue staticValues[] = {
                { "path", Filesystem_getPath, Filesystem_setPath, kJSPropertyAttributeDontDelete },
                { "type", Filesystem_getType, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
                { "exists", Filesystem_getExist, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
                { "size", Filesystem_getSize, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
                { 0, 0, 0, 0 }
            };
    
            classDefinition.className = "Filesystem";
            classDefinition.attributes = kJSClassAttributeNone;
            classDefinition.staticFunctions = staticFunctions;
            classDefinition.staticValues = staticValues;
            classDefinition.finalize = Filesystem_Finalize;
            classDefinition.callAsConstructor = Filesystem_CallAsConstructor;
    
            filesystem_class = JSClassCreate(&classDefinition);
        }
        return filesystem_class;
    }
    
    int main(int argc, const char * argv[]) {
    
        JSContextGroupRef contextGroup = JSContextGroupCreate();
        JSGlobalContextRef globalContext = JSGlobalContextCreateInGroup(contextGroup, nullptr);
        JSObjectRef globalObject = JSContextGetGlobalObject(globalContext);
    
        JSObjectRef functionObject = JSObjectMakeFunctionWithCallback(globalContext, JSStringCreateWithUTF8CString("log"), ObjectCallAsFunctionCallback);
        JSObjectSetProperty(globalContext, globalObject, JSStringCreateWithUTF8CString("log"), functionObject, kJSPropertyAttributeNone, nullptr);
    
        JSObjectRef filesystemObject = JSObjectMake(globalContext, FilesystemClass(), nullptr);
        JSObjectSetProperty(globalContext, globalObject, JSStringCreateWithUTF8CString("Filesystem"), filesystemObject, kJSPropertyAttributeNone, nullptr);
    
        JSEvaluateScript(globalContext, JSStringCreateWithUTF8CString("var fs = new Filesystem('/Users/{user}/Desktop/file');log(fs.exists);"), nullptr, nullptr, 1, nullptr);
    
        return 0;
    }
    

    【讨论】:

    • 谢谢!这将是我这样做的指南,
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多