Js C++手动绑定

一,示例js绑定c++的过程,实现在js中设定应用程序的“设计分辨率”以及在c++中调用js脚本。

二,手动绑定入口

        新建一个.h文件,此处定义为“JsbUtil.h”,定义函数:void register_jsb_util(JSContext *cx, JSObject *global);

       参数含义简介:

       cx:

              几乎所有的js api都要求我们传递一个上下文做为参数。在cocos2d-x中的js上下文在类ScriptingCore中定义:rt_。它就像是一台小机器,它涉及JavaScript代码和对象的很           多东西。它可以编译和执行脚本、获取和设置对象属性、调用JavaScript函数、一种类型转换为另一种JavaScript数据、创建对象,等等。

       global:

            全局js对象,全局对象包含所有可以在JavaScript代码中使用 的类、函数和变量。


三,实现绑定入口函数

        新建一个.cpp文件,此处命名为“JsbUtil.cpp”。

        首先声明两个变量:

               JsClass *js_util_class;  //要和c++绑定的js类

              JsObject *js_util_prototype; //在创建上述class类时的原型

       第二步中声明函数的实现如下:

/*
 此函数做的事情:
 1,为js_util_class分配空间
 2,设置js_util_class的各个属性
 3,设置要绑定的函数
 4,获取js_util_class的原型
 5,将js_util_class注册到全局属性中
*/
void register_jsb_util(JSContext *cx, JSObject *global)
{
    //js class的属性:https://developer.mozilla.org/en-US/docs/Mozilla/Projects/SpiderMonkey/JSAPI_reference/JSClass
    
    js_util_class = (JSClass*)calloc(1, sizeof(JSClass));
    js_util_class->name = "APP_UTIL";//class 的name属性,这样可以在js脚本中直接new APP_UTIL()来使用此类
    js_util_class->addProperty = JS_PropertyStub;//在添加新属性后被调用的函数。默认使用“JS_PropertyStub”
    js_util_class->delProperty = JS_PropertyStub; //删除属性时被调用的函数。默认使用“JS_PropertyStub”
    js_util_class->getProperty = JS_PropertyStub; //获取一个属性时调用的函数。这是js类的默认获取属性的方法。默认使用“JS_PropertyStub”。
    js_util_class->setProperty = JS_StrictPropertyStub; //在一个脚本中新建一个属性后它会在调用“addProperty”之后被调用。默认使用“JS_StrictPropertyStub”。
    js_util_class->enumerate = JS_EnumerateStub; //枚举(enumrate)对象属性的方法。默认使用“JS_EnumerateStub”。
    js_util_class->resolve = JS_ResolveStub; //分解类中属性的函数
    js_util_class->convert = JS_ConvertStub; //对类中属性值进行转换的函数
    js_util_class->finalize = js_utility_finalize; //类的对象释放时调用的析构函数,<span style="font-family: Arial, Helvetica, sans-serif;">需要声明到此函数的前面,下一步实现</span>

    //类的属性(成员变量)。0表明属性不是一 个集合.JS_HAS_PRIVATE: 类可以使用私有数据.JS_NEW_ENUMERATE: 返回由类定义的getObjectOps方法获取所有属性的一个新方法.JS_NEW_RESOLVE: 返回由类定义的 getObjectOps方法获取属性值的一个新方法
    js_util_class->flags = JSCLASS_HAS_RESERVED_SLOTS(2);
    
    //以上部分创建了一个js类,定义其属性:name,addProperty,delProperty, getProperty, setProperty, enumerate, resolve, convert, finalize, flags.
    
    //要注册的属性
    //struct JSPropertySpec {
    //    const char *name; //Name to assign the property
    
    //    int8 tinyid; //Obsolete since JSAPI 31 Unique ID number for the property to aid in resolving getProperty and setProperty method calls.
                       //This value should be zero if you are not using tinyIDs (i.e. the getter/setter function is only used by one property).
    
    //    uint8 flags; //Property attributes.
    
    //    JSPropertyOp getter; //Getter method for the property.
    
    //    JSPropertyOp setter; //Setter method for the property. If a property is read-only, it's setter is never called.
    //};
    static JSPropertySpec properties[] = {
        {0, 0, 0, 0, 0}
    };
    
    //实例函数
    //struct JSFunctionSpec {
    //    const char *name; //在js脚本中调用的函数名字;
    //    JSNative call; //映射的本地函数名称
    
    //    uint16 nargs; //The value used for Function.length. This no longer guarantees anything about the vp array.
    
    //    uint16 flags; //The bitwise OR of any number of property attributes and function flags, and optionally JSFUN_STUB_GSOPS.
    
    //    uint32 extra; //JSAPI 1.8 and earlier The lower 16 bits indicate the number of extra local roots the function desires,
                        //available at argv[MAX(nargs, argc)] onward. The upper 16 bits must be zero and are currently reserved.
                        //In older versions of SpiderMonkey, this field was a uint16 required to be 0.
    //};
    
    //#define JS_FN(name,call,nargs,flags)                                          \
    //{name, JSOP_WRAPPER(call), nargs, (flags) | JSFUN_STUB_GSOPS}
    //#define JS_FS_END JS_FS(NULL,NULL,0,0)
    
    static JSFunctionSpec funcs[] = {
        JS_FN("setDesignResolution", js_util_set_design_resolution, 3, JSPROP_ENUMERATE|JSPROP_PERMANENT),
        JS_FS_END
    };
    
    //类函数:看cocos2dx中的绑定此处绑定的是类的静态函数
    //    static JSFunctionSpec st_funcs[] = {
    //		JS_FN("create", js_cocos2dx_CCNode_create, 0, JSPROP_PERMANENT | JSPROP_ENUMERATE),
    //		JS_FS_END
    //	};
    static JSFunctionSpec st_funcs[] = {
      JS_FS_END
    };
    
    //初始化js类
    //JS_InitClass : Make a JSClass accessible to JavaScript code by creating its prototype, constructor, properties, and functions.
//    JSObject * JS_InitClass(JSContext *cx, //Pointer to a JS context from which to derive runtime information. Requires request.
                                             //In a JS_THREADSAFE build, the caller must be in a request on this JSContext.
    
//                            JSObject *obj, //Pointer to the "globals" object to use for initializing the class.
    
//                            JSObject *parent_proto,// Pointer to an object to be used as a prototype
    
//                            JSClass *clasp, //Pointer to the class structure to initialize. This structure defines the class for use by other API functions.
    
//                            JSNative constructor,//The constructor for the class. Its scope matches that of the obj argument.
                                                   //If constructor is NULL, then static_ps and static_fs must also be NULL.
//                            uintN nargs, //Number of arguments for the constructor.
    
//                            JSPropertySpec *ps, //Either NULL or a pointer to the first element of an array of JSPropertySpecs,
                                                  //terminated by the null JSPropertySpec, which can be written {0, 0, 0, 0, 0}. 要注册的属性
//                            JSFunctionSpec *fs, //Either NULL or a pointer to the first element of an array of JSFunctionSpecs, terminated by JS_FS_END.
                                                  // 要注册的函数
    
//                            JSPropertySpec *static_ps, //Either NULL or a pointer to the first element of an array of JSPropertySpecs, terminated by the null JSPropertySpec.
    
//                            JSFunctionSpec *static_fs);
    js_util_prototype = JS_InitClass(cx,
                                   global,
                                   NULL,
                                   js_util_class,
                                   js_util_constructor,//需要声明到此函数的前面,下一步实现
                                   0,
                                   properties,
                                   funcs,
                                   NULL,
                                   st_funcs);

    //注册到全局变量中
    JSBool found;
    JS_SetPropertyAttributes(cx, global, "APP_UTIL", JSPROP_ENUMERATE|JSPROP_READONLY, &found);
}

四,定义js类的析构和构造函数

        析够函数定义如下:

void js_utility_finalize(JSFreeOp *op, JSObject *obj)
{
    CCLOG("js_util_class is free : %p", obj);
}

  构造函数定义如下:

JSBool js_util_constructor(JSContext *cx, uint32_t argc, jsval *vp)
{
    if (argc != 0) {
        JS_ReportError(cx, "Wrong number of args: %d, was expecting: %d", argc, 0);
        return JS_FALSE;
    }
    
    JSObject *obj = JS_NewObject(cx, js_util_class, js_util_prototype, NULL);
    UtilHelper *cobj = new UtilHelper();//绑定的本地c++类,下一步实现
    
    //Link the native object with the javascript object
    js_proxy_t *p = jsb_new_proxy(cobj, obj);
    JS_AddNamedObjectRoot(cx, &p->obj, "APP_UTIL");
    
    //设置js构造函数的返回值为obj
    JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(obj));
    
    return JS_TRUE;
}

五,本地c++相关代码(UtilHelper)的实现

      在此简略实现,直接定义在“JsbUtil.cpp”文件中,现在只实现一个功能:设置项目的分辨率解决方案,如下:

class UtilHelper
{
public:
    void setDesignResolutionSize(float width, float height, ResolutionPolicy resolutionPolicy)
    {
        CCEGLView::sharedOpenGLView()->setDesignResolutionSize(width, height, resolutionPolicy);
    }
};

六,实现绑定函数js_util_set_design_resolution

/*
  绑定设置designResolution的函数
  根据当前的js object获取到其绑定的c++对象,再通过c++对象调用c++对象中的方法
*/
JSBool js_util_set_design_resolution(JSContext *cx, uint32_t argc, jsval *vp)
{
    if (argc != 3) {
        JS_ReportError(cx, "Wrong number of argc:%d, was expecting: %d", argc, 3);
        return JS_FALSE;
    }
    JSObject *obj_this = JS_THIS_OBJECT(cx, vp);
    js_proxy_t *proxy = jsb_get_js_proxy(obj_this);
    UtilHelper *cobj = (UtilHelper*)(proxy?proxy->ptr:NULL);
    JSB_PRECONDITION2(cobj, cx, JS_FALSE, "Invalid Native object");
    
    jsval *argv = JS_ARGV(cx, vp);
    
    int width = 0;
    if (JSVAL_IS_INT(argv[0])) {
        jsval_to_int32(cx, argv[0], &width);
    }
    
    int height = 0;
    if (JSVAL_IS_INT(argv[1])) {
        jsval_to_int32(cx, argv[1], &height);
    }
    
    std::string data;
    if(JSVAL_IS_STRING(argv[2])){
        jsval_to_std_string(cx, argv[2], &data);
    }
    
    ResolutionPolicy policy = kResolutionUnKnown;
    if (data == std::string("kResolutionExactFit")) {
        policy = kResolutionExactFit;
    }else if(data == std::string("kResolutionNoBorder")){
        policy = kResolutionNoBorder;
    }else if(data == std::string("kResolutionFixedHeight")){
        policy = kResolutionFixedHeight;
    }else if(data == std::string("kResolutionFixedWidth")){
        policy = kResolutionFixedWidth;
    }else if(data == std::string("kResolutionShowAll")){
        policy = kResolutionShowAll;
    }
    
    cobj->setDesignResolutionSize(width, height, policy);
    
    return JS_TRUE;
}


七,注册调用

       新建test_util.js文件放在Resource/script目录下,添加如下代码:

require("jsb.js")

var director = cc.Director.getInstance();
var winSize = director.getWinSize();
var scene = cc.Scene.create();
var testSprite = cc.Sprite.create('HelloWorld.png'); //使用系统自带的图片,分辨率为480x320
scene.addChild(testSprite);
testSprite.setPosition(cc.p(winSize.width/2, winSize.height/2));

director.runWithScene(scene);
     修改AppDelegate.cpp:

      1,添加绑定:sc->addRegisterCallback(register_jsb_util);

      2,修改执行的脚本为test_util.js:ScriptingCore::getInstance()->runScript("script/test_util.js");

      之后使用480x320的模拟器效果图如下:

      

切换到分辨率大的模拟器后不能再全屏:


在require("jsb.js")下添加如下代码:

var util = new APP_UTIL();
util.setDesignResolution(480, 320, 'kResolutionFixedHeight');

之后运行效果如下:


 九,添加c++回调脚本的功能

         在UtilHelper中添加如下代码:

    
    void CallBackJs()
    {
        JSContext *cx = ScriptingCore::getInstance()->getGlobalContext();
        JSObject *jsobj = JS_NewObject(cx, NULL, NULL, NULL);
        
        // 组织传递给脚本的参数
        int attr1Val = 1;
        jsval vp;
        vp = int32_to_jsval(cx, attr1Val);
        JS_SetProperty(cx, jsobj, "myAttr1", &vp);
        
        jsval args = OBJECT_TO_JSVAL(jsobj);
        
        //转给脚本
        ScriptingCore::getInstance()->executeFunctionWithOwner(OBJECT_TO_JSVAL(m_pJsDelegate), "onTestCallJs", 1, &args);
    }
    
    void SetJsDelegate(JSObject *pDelegate) {
        m_pJsDelegate = pDelegate;
    }
    
private:
    JSObject *m_pJsDelegate;
      在方法setDesignResolutionSize调用callBackJs

    void setDesignResolutionSize(float width, float height, ResolutionPolicy resolutionPolicy)
    {
        CCEGLView::sharedOpenGLView()->setDesignResolutionSize(width, height, resolutionPolicy);
        CallBackJs();
    }
        在js_util_constructor中设置util关联的js类:

        

JSBool js_util_constructor(JSContext *cx, uint32_t argc, jsval *vp)
{
    if (argc != 0) {
        JS_ReportError(cx, "Wrong number of args: %d, was expecting: %d", argc, 0);
        return JS_FALSE;
    }
    
    JSObject *obj = JS_NewObject(cx, js_util_class, js_util_prototype, NULL);
    UtilHelper *cobj = new UtilHelper();
    cobj->SetJsDelegate(obj); //添加此句
    .....
}

在test_util.js脚本中实现onTestCallJs:

var util = new APP_UTIL();
util.onTestCallJs = function(arg) {
	cc.log('call by c++, arg is = ' + JSON.stringify(arg));//打印出c++传递来的参数
};
再次运行程序,在xcode的输出窗口可以看到如下log:


十,至此,js\C++手动绑定,混合调用示例书写完毕。

        相关参考:

           JavaScript-C/C++ (SpiderMonkey) 引擎嵌入开发指南(中文向导)

            JSAPI_reference

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值