Cocos2d-js JSB绑定学习笔记

来源:互联网 发布:河源优化公司 编辑:程序博客网 时间:2024/05/16 09:44

cocos2d js 的jsb绑定简单来讲就是在C++底层实现一些类库,然后经过一些特定处理可以在js端进行调用的方法。此文档用于记录手动绑定C++自定义类库到js端的实现过程。

此jsb绑定基于cocos2d-js 3.6.1测试使用。

————————————————朴实无华分割线,以上内容不重要————————————————

1、向自定义的JSB绑定目录JSBCustom添加一个需要绑定的JSBClass类

JSBClass.h文件内容如下:

#pragma once#include "cocos2d.h"#include <string>USING_NS_CC;namespace jsbcustom{    void globalFunc_jsbTest();    class JSBClass : public Ref    {    public:        JSBClass();        CREATE_FUNC(JSBClass);        virtual bool init();        void jsbTestShow(std::string info);        int jsbTestGetInt();        void jsbTestCallBack(std::function<void(int)> callback);    };}

JSBClass.cpp文件内容如下:

#include "JSBClass.h"void jsbcustom::globalFunc_jsbTest(){    log("imcustom::globalFunc_jsbTest call!!!");}jsbcustom::JSBClass::JSBClass(){    log("jsbcustom::JSBClass::JSBClass call!!!");}bool jsbcustom::JSBClass::init(){    log("jsbcustom::JSBClass::init call by create!!!");    return true;}void jsbcustom::JSBClass::jsbTestShow(std::string info){    log("jsbcustom::JSBClass::jsbTestShow call, show parameter = %s!!!",info.c_str());}int jsbcustom::JSBClass::jsbTestGetInt(){    log("jsbcustom::JSBClass::jsbTestGetInt call,return test value 73!!!");    return 73;}void jsbcustom::JSBClass::jsbTestCallBack(std::function<void(int)> callback){    log("jsbcustom::JSBClass::jsbTestCallBack call,and call callback with \"parameter=73\" immediately!!!");    callback(73);}

上述c++类其实就是普通的符合cocos2d-x自动内存管理规范的c++类,由于只是测试,所以只是使用了最简单基本的实现。

2、定义手动绑定处理文件jsb_custom_auto.h和jsb_custom_auto.cpp

jsb_custom_auto.h声明对JSBClass进行js绑定的方法:

#pragma once#include "jsapi.h";#include "jsfriendapi.h"#include "ScriptingCore.h"// 自定义jsbcustom命名空间下的类或函数等的jsb注册入口void register_all_jsbcustom_jsb(JSContext* bindJSContext,JS::HandleObject bindObj);// 注册jsbcustom命名空间下的函数void jsb_register_jsbcustom_global(JSContext *bindJSContext, JS::HandleObject obj);bool jsb_jsbcustom_globalFunc_jsbTest(JSContext *bindJSContext, uint32_t argc, jsval *vp);         // 具体绑定方法实现// 注册jsbcustom命名空间下的类void jsb_register_jsbcustom_JSBCLASS_class(JSContext *bindJSContext, JS::HandleObject obj);        // 具体绑定类的绑定实现bool jsb_jsbcustom_JSBCLASS_constructor(JSContext *bindJSContext, uint32_t argc, jsval *vp);       // 具体绑定类的构造方法绑定实现void jsb_jsbcustom_JSBCLASS_finalize(JSFreeOp *fop, JSObject *obj);                                // 具体绑定类的析构方法绑定实现bool jsb_jsbcustom_JSBCLASS_st_create(JSContext *bindJSContext, uint32_t argc, jsval *vp);         // 具体绑定类的静态create方法绑定实现bool jsb_jsbcustom_JSBCLASS_jsbTestShow(JSContext *bindJSContext, uint32_t argc, jsval *vp);       // 具体绑定类的具体方法绑定实现bool jsb_jsbcustom_JSBCLASS_jsbTestGetInt(JSContext *bindJSContext, uint32_t argc, jsval *vp);     // 具体绑定类的具体方法绑定实现bool jsb_jsbcustom_JSBCLASS_jsbTestCallBack(JSContext *bindJSContext, uint32_t argc, jsval *vp);   // 具体绑定类的具体方法绑定实现bool jsb_jsbcustom_JSBCLASS_jsbTest_callback(JSContext *bindJSContext, uint32_t argc, jsval *vp);  // 具体绑定类的属性方法回调实现

其中jsb_custom_auto.cpp进行具体的绑定处理:

#include "jsb_custom_auto.h"#include "cocos2d.h"#include "JSBClass.h"#include "cocos2d_specifics.hpp"#include <string>void register_all_jsbcustom_jsb(JSContext* bindJSContext,JS::HandleObject bindObj){    JS::RootedObject newBindObj(bindJSContext);    // 第一步:注册命名空间:jsbcustom,(后续二三可以不分先后)    get_or_create_js_obj(bindJSContext, bindObj, "jsbcustom", &newBindObj);    // 第二步:注册命名空间下的全局函数    jsb_register_jsbcustom_global(bindJSContext,newBindObj);    // 第三步:注册命名空间下的类    jsb_register_jsbcustom_JSBCLASS_class(bindJSContext,newBindObj);}void jsb_register_jsbcustom_global(JSContext *bindJSContext, JS::HandleObject bindObj){    JS_DefineFunction(bindJSContext, bindObj, "st_jsbTest", jsb_jsbcustom_globalFunc_jsbTest, 0, 0);}bool jsb_jsbcustom_globalFunc_jsbTest(JSContext *bindJSContext, uint32_t argc, jsval *vp){    if (argc==0)    {        auto args = JS::CallArgsFromVp(argc, vp);        jsbcustom::globalFunc_jsbTest();        args.rval().setUndefined();        return true;    }    JS_ReportError(bindJSContext, "jsb_jsbcustom_globalFunc_jsbTest: wrong number of arguments: %d, was expecting %d", argc, 0);    return false;}void jsb_register_jsbcustom_JSBCLASS_class(JSContext *bindJSContext, JS::HandleObject obj){    // C++类要绑定到的js类句柄    JSClass *jsb_jsbcustom_jsbclass_class;    jsb_jsbcustom_jsbclass_class = (JSClass *)calloc(1, sizeof(JSClass));    jsb_jsbcustom_jsbclass_class->name = "JSBCLASS";                            // 新类绑定变化项:名字(JS中调用的对应类名)    jsb_jsbcustom_jsbclass_class->addProperty = JS_PropertyStub;    jsb_jsbcustom_jsbclass_class->delProperty = JS_DeletePropertyStub;    jsb_jsbcustom_jsbclass_class->getProperty = JS_PropertyStub;    jsb_jsbcustom_jsbclass_class->setProperty = JS_StrictPropertyStub;    jsb_jsbcustom_jsbclass_class->enumerate = JS_EnumerateStub;    jsb_jsbcustom_jsbclass_class->resolve = JS_ResolveStub;    jsb_jsbcustom_jsbclass_class->convert = JS_ConvertStub;    jsb_jsbcustom_jsbclass_class->finalize = jsb_jsbcustom_JSBCLASS_finalize;   // 新类绑定变化项:析构处理    jsb_jsbcustom_jsbclass_class->flags = JSCLASS_HAS_RESERVED_SLOTS(2);    static JSPropertySpec properties[] =        // 新类绑定变化项:成员变量    {        JS_PS_END    };    static JSFunctionSpec funcs[] =             // 新类绑定变化项:成员函数    {        JS_FN("jsbTestShow", jsb_jsbcustom_JSBCLASS_jsbTestShow, 1, JSPROP_PERMANENT | JSPROP_ENUMERATE),        JS_FN("jsbTestGetInt", jsb_jsbcustom_JSBCLASS_jsbTestGetInt, 0, JSPROP_PERMANENT | JSPROP_ENUMERATE),        JS_FN("jsbTestCallBack", jsb_jsbcustom_JSBCLASS_jsbTestCallBack, 1, JSPROP_PERMANENT | JSPROP_ENUMERATE),        JS_FN("jsbTest_callback", jsb_jsbcustom_JSBCLASS_jsbTest_callback, 1, JSPROP_PERMANENT | JSPROP_ENUMERATE),        JS_FS_END    };    static JSPropertySpec st_properties[] =     // 新类绑定变化项:静态变量    {        JS_PS_END    };    static JSFunctionSpec st_funcs[] =          // 新类绑定变化项:静态函数    {        JS_FN("create", jsb_jsbcustom_JSBCLASS_st_create, 0, JSPROP_PERMANENT | JSPROP_ENUMERATE),        JS_FS_END    };    // C++类要绑定到的js类原型句柄    JSObject *jsb_jsbcustom_jsbclass_prototype;    jsb_jsbcustom_jsbclass_prototype = JS_InitClass(        bindJSContext, obj,        JS::NullPtr(),                              // 新类绑定变化项:基类句柄        jsb_jsbcustom_jsbclass_class,        jsb_jsbcustom_JSBCLASS_constructor, 0,      // 新类绑定变化项:构造函数及其参数个数        properties,        funcs,        st_properties,        st_funcs);    // 添加js类到js信息Hash表    TypeTest<jsbcustom::JSBClass> t;    std::string typeName = t.s_name();    if (_js_global_type_map.find(typeName) == _js_global_type_map.end())    {        js_type_class_t *p = (js_type_class_t *)malloc(sizeof(js_type_class_t));        p->jsclass = jsb_jsbcustom_jsbclass_class;        p->proto = jsb_jsbcustom_jsbclass_prototype;        p->parentProto = NULL; // 新类绑定变化项:基类原型句柄        _js_global_type_map.insert(std::make_pair(typeName, p));    }}bool jsb_jsbcustom_JSBCLASS_constructor(JSContext *bindJSContext, uint32_t argc, jsval *vp){    if (argc==0)    {        auto args = JS::CallArgsFromVp(argc, vp);        auto jsret = JSVAL_NULL;        auto ret = new jsbcustom::JSBClass();        if (ret)         {            ret->autorelease();            auto jsProxy = js_get_or_create_proxy<jsbcustom::JSBClass>(bindJSContext, (jsbcustom::JSBClass*)ret);            jsret = OBJECT_TO_JSVAL(jsProxy->obj);        }         args.rval().set(jsret);        return true;    }    JS_ReportError(bindJSContext, "jsb_jsbcustom_JSBCLASS_constructor: wrong number of arguments: %d, was expecting %d", argc, 0);    return false;}void jsb_jsbcustom_JSBCLASS_finalize(JSFreeOp *fop, JSObject *obj){    log("jsbindings: finalizing JS object %p (JSBCLASS)", obj);}bool jsb_jsbcustom_JSBCLASS_st_create(JSContext *bindJSContext, uint32_t argc, jsval *vp){    if (argc == 0)     {        auto args = JS::CallArgsFromVp(argc, vp);        auto jsret = JSVAL_NULL;        auto ret = jsbcustom::JSBClass::create();        if (ret)         {            auto jsProxy = js_get_or_create_proxy<jsbcustom::JSBClass>(bindJSContext, (jsbcustom::JSBClass*)ret);            jsret = OBJECT_TO_JSVAL(jsProxy->obj);        }         args.rval().set(jsret);        return true;    }    JS_ReportError(bindJSContext, "jsb_jsbcustom_JSBCLASS_st_create : wrong number of arguments: %d, was expecting %d", argc, 0);    return false;}bool jsb_jsbcustom_JSBCLASS_jsbTestShow(JSContext *bindJSContext, uint32_t argc, jsval *vp){    if (argc == 1)    {        JS::CallArgs args = JS::CallArgsFromVp(argc, vp);        js_proxy_t *proxy = jsb_get_js_proxy(JS::RootedObject(bindJSContext, args.thisv().toObjectOrNull()));        auto cobj = (jsbcustom::JSBClass*)(proxy ? proxy->ptr : NULL);        JSB_PRECONDITION2(cobj, bindJSContext, false, "js_imcustom_class_jsbTest: Invalid Native Object");        JSString *jsstr = JS::ToString( bindJSContext, args.get(0));        JSStringWrapper jsstrw(jsstr);        std::string arg0(jsstrw.get());        cobj->jsbTestShow(arg0);        args.rval().setUndefined();        return true;    }    JS_ReportError(bindJSContext, "jsb_jsbcustom_JSBCLASS_jsbTestShow : wrong number of arguments: %d, was expecting %d", argc, 1);    return false;}bool jsb_jsbcustom_JSBCLASS_jsbTestGetInt(JSContext *bindJSContext, uint32_t argc, jsval *vp){    if (argc == 0)     {        JS::CallArgs args = JS::CallArgsFromVp(argc, vp);        js_proxy_t *proxy = jsb_get_js_proxy(JS::RootedObject(bindJSContext, args.thisv().toObjectOrNull()));        auto cobj = (jsbcustom::JSBClass*)(proxy ? proxy->ptr : NULL);        JSB_PRECONDITION2( cobj, bindJSContext, false, "js_imcustom_class_jsbGetTest : Invalid Native Object");        int ret = cobj->jsbTestGetInt();        jsval jsret = JSVAL_NULL;        jsret = INT_TO_JSVAL(ret);        args.rval().set(jsret);        return true;    }    JS_ReportError(bindJSContext, "jsb_jsbcustom_JSBCLASS_jsbTestGetInt : wrong number of arguments: %d, was expecting %d", argc, 0);    return false;}bool jsb_jsbcustom_JSBCLASS_jsbTestCallBack(JSContext *bindJSContext, uint32_t argc, jsval *vp){    if (argc >= 1)     {        JS::CallArgs args = JS::CallArgsFromVp(argc, vp);        JS::RootedObject obj(bindJSContext, args.thisv().toObjectOrNull());        js_proxy_t *proxy = jsb_get_js_proxy(obj);        auto cobj = (jsbcustom::JSBClass*)(proxy ? proxy->ptr : NULL);        JSB_PRECONDITION2( cobj, bindJSContext, false, "jsb_register_imcustom_jsbCallBack : Invalid Native Object");        std::function<void(int)> callback = [&](int state)        {            JS::Heap<JS::Value> js_TestCallback(JSVAL_VOID);            js_TestCallback = args.get(0);            JS::AddNamedValueRoot(bindJSContext, &js_TestCallback, "imcustom_jsbCallBack_func");            JS::Heap<JS::Value> js_TestCallbackThis(JSVAL_VOID);            js_TestCallbackThis = argc==2?args.get(1):OBJECT_TO_JSVAL(obj);            JS::AddNamedValueRoot(bindJSContext, &js_TestCallbackThis, "imcustom_jsbCallBack_this");            if(!js_TestCallback.isNullOrUndefined())             {                jsval data = INT_TO_JSVAL(state);                auto argsVal = JS::HandleValueArray::fromMarkedLocation(1, &data);                JS::RootedValue retval(bindJSContext);                JS_CallFunctionValue(bindJSContext, JS::RootedObject(bindJSContext, js_TestCallbackThis.toObjectOrNull()), JS::RootedValue(bindJSContext, js_TestCallback.get()), argsVal, &retval);            }        };        cobj->jsbTestCallBack(callback);        args.rval().setUndefined();        return true;    }    JS_ReportError(bindJSContext, "jsb_jsbcustom_JSBCLASS_jsbTestCallBack : wrong number of arguments: %d, was expecting %d|%d", argc, 1,2);    return false;}bool jsb_jsbcustom_JSBCLASS_jsbTest_callback(JSContext *bindJSContext, uint32_t argc, jsval *vp){    if (argc == 0)     {        JS::CallArgs args = JS::CallArgsFromVp(argc, vp);        js_proxy_t *proxy = jsb_get_js_proxy(JS::RootedObject(bindJSContext, args.thisv().toObjectOrNull()));        if (proxy)         {            jsval dataVal[2];            dataVal[0] = INT_TO_JSVAL(32);            dataVal[1] = UINT_TO_JSVAL(88);            ScriptingCore::getInstance()->executeFunctionWithOwner(OBJECT_TO_JSVAL(proxy->obj), "callback", 2, dataVal);        }        args.rval().setUndefined();        return true;    }    JS_ReportError(bindJSContext, "jsb_jsbcustom_JSBCLASS_jsbTest_callback : wrong number of arguments: %d, was expecting %d", argc, 0);    return false;}

3、执行绑定初始化

AppDelegate::applicationDidFinishLaunching()方法中进行新绑定注册:

sc->addRegisterCallback(register_all_jsbcustom_jsb);

4、编译新类库后JS端测试运行

    // jsbcustom命名空间下全局方法测试    jsbcustom.st_jsbTest();    // 构造函数绑定测试    var jsbcustomVal = new jsbcustom.JSBCLASS();    // create静态方法绑定测试    var s_jsbcustomVal = jsbcustom.JSBCLASS.create();    // jsbTestShow成员方法绑定测试    jsbcustomVal.jsbTestShow("call from js!!!");    // jsbTestGetInt成员方法绑定测试    var getjsbInt = jsbcustomVal.jsbTestGetInt();    cc.log("call from js,get a result = %s!!!",getjsbInt);    // jsbTestCallBack成员方法绑定测试    jsbcustomVal.jsbTestCallBack(function(state)    {        cc.log("set a callback from js,get parameter state = %s!!!,state");    },this);    // 回调成员变量句柄callback测试    jsbcustomVal.callback = function(state1,state2)    {        cc.log("set a \"jsbcustomVal.callback\"callback from js,get state1 = %s,state2=%s!!!",state1,state2);    };    jsbcustomVal.jsbTest_callback();

结束

3 0
原创粉丝点击