2017-10-25 7 views
1

C++ 프로젝트에서 JavascriptCore로 작업하고 있으며 C++ 클래스를 javascript에 노출하는 방법을 알지 못합니다. ++C++에서 JSExport 및 JavascriptCore를 사용하는 방법

@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]; 

하지만 C로 어떻게 JSExport을 번역하는 아이디어와 프로토콜을하지 않은 : 오브젝티브 C의 예를 들어이 같은 것입니다.

답변

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; 
} 
+0

감사합니다! 이건 내 가이드가 될거야. –