Js C++手动绑定(案例1)

来源:互联网 发布:为什么要学c语言 编辑:程序博客网 时间:2024/06/16 03:55

一,示例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类时的原型

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

[cpp] view plain copy
  1. /* 
  2.  此函数做的事情: 
  3.  1,为js_util_class分配空间 
  4.  2,设置js_util_class的各个属性 
  5.  3,设置要绑定的函数 
  6.  4,获取js_util_class的原型 
  7.  5,将js_util_class注册到全局属性中 
  8. */  
  9. void register_jsb_util(JSContext *cx, JSObject *global)  
  10. {  
  11.     //js class的属性:https://developer.mozilla.org/en-US/docs/Mozilla/Projects/SpiderMonkey/JSAPI_reference/JSClass  
  12.       
  13.     js_util_class = (JSClass*)calloc(1, sizeof(JSClass));  
  14.     js_util_class->name = "APP_UTIL";//class 的name属性,这样可以在js脚本中直接new APP_UTIL()来使用此类  
  15.     js_util_class->addProperty = JS_PropertyStub;//在添加新属性后被调用的函数。默认使用“JS_PropertyStub”  
  16.     js_util_class->delProperty = JS_PropertyStub; //删除属性时被调用的函数。默认使用“JS_PropertyStub”  
  17.     js_util_class->getProperty = JS_PropertyStub; //获取一个属性时调用的函数。这是js类的默认获取属性的方法。默认使用“JS_PropertyStub”。  
  18.     js_util_class->setProperty = JS_StrictPropertyStub; //在一个脚本中新建一个属性后它会在调用“addProperty”之后被调用。默认使用“JS_StrictPropertyStub”。  
  19.     js_util_class->enumerate = JS_EnumerateStub; //枚举(enumrate)对象属性的方法。默认使用“JS_EnumerateStub”。  
  20.     js_util_class->resolve = JS_ResolveStub; //分解类中属性的函数  
  21.     js_util_class->convert = JS_ConvertStub; //对类中属性值进行转换的函数  
  22.     js_util_class->finalize = js_utility_finalize; //类的对象释放时调用的析构函数,<span style="font-family: Arial, Helvetica, sans-serif;">需要声明到此函数的前面,下一步实现</span>  
  23.   
  24.     //类的属性(成员变量)。0表明属性不是一 个集合.JS_HAS_PRIVATE: 类可以使用私有数据.JS_NEW_ENUMERATE: 返回由类定义的getObjectOps方法获取所有属性的一个新方法.JS_NEW_RESOLVE: 返回由类定义的 getObjectOps方法获取属性值的一个新方法  
  25.     js_util_class->flags = JSCLASS_HAS_RESERVED_SLOTS(2);  
  26.       
  27.     //以上部分创建了一个js类,定义其属性:name,addProperty,delProperty, getProperty, setProperty, enumerate, resolve, convert, finalize, flags.  
  28.       
  29.     //要注册的属性  
  30.     //struct JSPropertySpec {  
  31.     //    const char *name; //Name to assign the property  
  32.       
  33.     //    int8 tinyid; //Obsolete since JSAPI 31 Unique ID number for the property to aid in resolving getProperty and setProperty method calls.  
  34.                        //This value should be zero if you are not using tinyIDs (i.e. the getter/setter function is only used by one property).  
  35.       
  36.     //    uint8 flags; //Property attributes.  
  37.       
  38.     //    JSPropertyOp getter; //Getter method for the property.  
  39.       
  40.     //    JSPropertyOp setter; //Setter method for the property. If a property is read-only, it's setter is never called.  
  41.     //};  
  42.     static JSPropertySpec properties[] = {  
  43.         {0, 0, 0, 0, 0}  
  44.     };  
  45.       
  46.     //实例函数  
  47.     //struct JSFunctionSpec {  
  48.     //    const char *name; //在js脚本中调用的函数名字;  
  49.     //    JSNative call; //映射的本地函数名称  
  50.       
  51.     //    uint16 nargs; //The value used for Function.length. This no longer guarantees anything about the vp array.  
  52.       
  53.     //    uint16 flags; //The bitwise OR of any number of property attributes and function flags, and optionally JSFUN_STUB_GSOPS.  
  54.       
  55.     //    uint32 extra; //JSAPI 1.8 and earlier The lower 16 bits indicate the number of extra local roots the function desires,  
  56.                         //available at argv[MAX(nargs, argc)] onward. The upper 16 bits must be zero and are currently reserved.  
  57.                         //In older versions of SpiderMonkey, this field was a uint16 required to be 0.  
  58.     //};  
  59.       
  60.     //#define JS_FN(name,call,nargs,flags)                                          \  
  61.     //{name, JSOP_WRAPPER(call), nargs, (flags) | JSFUN_STUB_GSOPS}  
  62.     //#define JS_FS_END JS_FS(NULL,NULL,0,0)  
  63.       
  64.     static JSFunctionSpec funcs[] = {  
  65.         JS_FN("setDesignResolution", js_util_set_design_resolution, 3, JSPROP_ENUMERATE|JSPROP_PERMANENT),  
  66.         JS_FS_END  
  67.     };  
  68.       
  69.     //类函数:看cocos2dx中的绑定此处绑定的是类的静态函数  
  70.     //    static JSFunctionSpec st_funcs[] = {  
  71.     //      JS_FN("create", js_cocos2dx_CCNode_create, 0, JSPROP_PERMANENT | JSPROP_ENUMERATE),  
  72.     //      JS_FS_END  
  73.     //  };  
  74.     static JSFunctionSpec st_funcs[] = {  
  75.       JS_FS_END  
  76.     };  
  77.       
  78.     //初始化js类  
  79.     //JS_InitClass : Make a JSClass accessible to JavaScript code by creating its prototype, constructor, properties, and functions.  
  80. //    JSObject * JS_InitClass(JSContext *cx, //Pointer to a JS context from which to derive runtime information. Requires request.  
  81.                                              //In a JS_THREADSAFE build, the caller must be in a request on this JSContext.  
  82.       
  83. //                            JSObject *obj, //Pointer to the "globals" object to use for initializing the class.  
  84.       
  85. //                            JSObject *parent_proto,// Pointer to an object to be used as a prototype  
  86.       
  87. //                            JSClass *clasp, //Pointer to the class structure to initialize. This structure defines the class for use by other API functions.  
  88.       
  89. //                            JSNative constructor,//The constructor for the class. Its scope matches that of the obj argument.  
  90.                                                    //If constructor is NULL, then static_ps and static_fs must also be NULL.  
  91. //                            uintN nargs, //Number of arguments for the constructor.  
  92.       
  93. //                            JSPropertySpec *ps, //Either NULL or a pointer to the first element of an array of JSPropertySpecs,  
  94.                                                   //terminated by the null JSPropertySpec, which can be written {0, 0, 0, 0, 0}. 要注册的属性  
  95. //                            JSFunctionSpec *fs, //Either NULL or a pointer to the first element of an array of JSFunctionSpecs, terminated by JS_FS_END.  
  96.                                                   // 要注册的函数  
  97.       
  98. //                            JSPropertySpec *static_ps, //Either NULL or a pointer to the first element of an array of JSPropertySpecs, terminated by the null JSPropertySpec.  
  99.       
  100. //                            JSFunctionSpec *static_fs);  
  101.     js_util_prototype = JS_InitClass(cx,  
  102.                                    global,  
  103.                                    NULL,  
  104.                                    js_util_class,  
  105.                                    js_util_constructor,//需要声明到此函数的前面,下一步实现  
  106.                                    0,  
  107.                                    properties,  
  108.                                    funcs,  
  109.                                    NULL,  
  110.                                    st_funcs);  
  111.   
  112.     //注册到全局变量中  
  113.     JSBool found;  
  114.     JS_SetPropertyAttributes(cx, global, "APP_UTIL", JSPROP_ENUMERATE|JSPROP_READONLY, &found);  
  115. }  

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

        析够函数定义如下:

[cpp] view plain copy
  1. void js_utility_finalize(JSFreeOp *op, JSObject *obj)  
  2. {  
  3.     CCLOG("js_util_class is free : %p", obj);  
  4. }  

  构造函数定义如下:

[cpp] view plain copy
  1. JSBool js_util_constructor(JSContext *cx, uint32_t argc, jsval *vp)  
  2. {  
  3.     if (argc != 0) {  
  4.         JS_ReportError(cx, "Wrong number of args: %d, was expecting: %d", argc, 0);  
  5.         return JS_FALSE;  
  6.     }  
  7.       
  8.     JSObject *obj = JS_NewObject(cx, js_util_class, js_util_prototype, NULL);  
  9.     UtilHelper *cobj = new UtilHelper();//绑定的本地c++类,下一步实现  
  10.       
  11.     //Link the native object with the javascript object  
  12.     js_proxy_t *p = jsb_new_proxy(cobj, obj);  
  13.     JS_AddNamedObjectRoot(cx, &p->obj, "APP_UTIL");  
  14.       
  15.     //设置js构造函数的返回值为obj  
  16.     JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(obj));  
  17.       
  18.     return JS_TRUE;  
  19. }  

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

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

[cpp] view plain copy
  1. class UtilHelper  
  2. {  
  3. public:  
  4.     void setDesignResolutionSize(float width, float height, ResolutionPolicy resolutionPolicy)  
  5.     {  
  6.         CCEGLView::sharedOpenGLView()->setDesignResolutionSize(width, height, resolutionPolicy);  
  7.     }  
  8. };  

六,实现绑定函数js_util_set_design_resolution

[cpp] view plain copy
  1. /* 
  2.   绑定设置designResolution的函数 
  3.   根据当前的js object获取到其绑定的c++对象,再通过c++对象调用c++对象中的方法 
  4. */  
  5. JSBool js_util_set_design_resolution(JSContext *cx, uint32_t argc, jsval *vp)  
  6. {  
  7.     if (argc != 3) {  
  8.         JS_ReportError(cx, "Wrong number of argc:%d, was expecting: %d", argc, 3);  
  9.         return JS_FALSE;  
  10.     }  
  11.     JSObject *obj_this = JS_THIS_OBJECT(cx, vp);  
  12.     js_proxy_t *proxy = jsb_get_js_proxy(obj_this);  
  13.     UtilHelper *cobj = (UtilHelper*)(proxy?proxy->ptr:NULL);  
  14.     JSB_PRECONDITION2(cobj, cx, JS_FALSE, "Invalid Native object");  
  15.       
  16.     jsval *argv = JS_ARGV(cx, vp);  
  17.       
  18.     int width = 0;  
  19.     if (JSVAL_IS_INT(argv[0])) {  
  20.         jsval_to_int32(cx, argv[0], &width);  
  21.     }  
  22.       
  23.     int height = 0;  
  24.     if (JSVAL_IS_INT(argv[1])) {  
  25.         jsval_to_int32(cx, argv[1], &height);  
  26.     }  
  27.       
  28.     std::string data;  
  29.     if(JSVAL_IS_STRING(argv[2])){  
  30.         jsval_to_std_string(cx, argv[2], &data);  
  31.     }  
  32.       
  33.     ResolutionPolicy policy = kResolutionUnKnown;  
  34.     if (data == std::string("kResolutionExactFit")) {  
  35.         policy = kResolutionExactFit;  
  36.     }else if(data == std::string("kResolutionNoBorder")){  
  37.         policy = kResolutionNoBorder;  
  38.     }else if(data == std::string("kResolutionFixedHeight")){  
  39.         policy = kResolutionFixedHeight;  
  40.     }else if(data == std::string("kResolutionFixedWidth")){  
  41.         policy = kResolutionFixedWidth;  
  42.     }else if(data == std::string("kResolutionShowAll")){  
  43.         policy = kResolutionShowAll;  
  44.     }  
  45.       
  46.     cobj->setDesignResolutionSize(width, height, policy);  
  47.       
  48.     return JS_TRUE;  
  49. }  


七,注册调用

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

[javascript] view plain copy
  1. require("jsb.js")  
  2.   
  3. var director = cc.Director.getInstance();  
  4. var winSize = director.getWinSize();  
  5. var scene = cc.Scene.create();  
  6. var testSprite = cc.Sprite.create('HelloWorld.png'); //使用系统自带的图片,分辨率为480x320  
  7. scene.addChild(testSprite);  
  8. testSprite.setPosition(cc.p(winSize.width/2, winSize.height/2));  
  9.   
  10. 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")下添加如下代码:

[javascript] view plain copy
  1. var util = new APP_UTIL();  
  2. util.setDesignResolution(480, 320, 'kResolutionFixedHeight');  

之后运行效果如下:


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

         在UtilHelper中添加如下代码:

[cpp] view plain copy
  1.       
  2.     void CallBackJs()  
  3.     {  
  4.         JSContext *cx = ScriptingCore::getInstance()->getGlobalContext();  
  5.         JSObject *jsobj = JS_NewObject(cx, NULL, NULL, NULL);  
  6.           
  7.         // 组织传递给脚本的参数  
  8.         int attr1Val = 1;  
  9.         jsval vp;  
  10.         vp = int32_to_jsval(cx, attr1Val);  
  11.         JS_SetProperty(cx, jsobj, "myAttr1", &vp);  
  12.           
  13.         jsval args = OBJECT_TO_JSVAL(jsobj);  
  14.           
  15.         //转给脚本  
  16.         ScriptingCore::getInstance()->executeFunctionWithOwner(OBJECT_TO_JSVAL(m_pJsDelegate), "onTestCallJs", 1, &args);  
  17.     }  
  18.       
  19.     void SetJsDelegate(JSObject *pDelegate) {  
  20.         m_pJsDelegate = pDelegate;  
  21.     }  
  22.       
  23. private:  
  24.     JSObject *m_pJsDelegate;  
      在方法setDesignResolutionSize调用callBackJs

[cpp] view plain copy
  1. void setDesignResolutionSize(float width, float height, ResolutionPolicy resolutionPolicy)  
  2. {  
  3.     CCEGLView::sharedOpenGLView()->setDesignResolutionSize(width, height, resolutionPolicy);  
  4.     CallBackJs();  
  5. }  
        在js_util_constructor中设置util关联的js类:

        

[cpp] view plain copy
  1. JSBool js_util_constructor(JSContext *cx, uint32_t argc, jsval *vp)  
  2. {  
  3.     if (argc != 0) {  
  4.         JS_ReportError(cx, "Wrong number of args: %d, was expecting: %d", argc, 0);  
  5.         return JS_FALSE;  
  6.     }  
  7.       
  8.     JSObject *obj = JS_NewObject(cx, js_util_class, js_util_prototype, NULL);  
  9.     UtilHelper *cobj = new UtilHelper();  
  10.     cobj->SetJsDelegate(obj); //添加此句  
  11.     .....  
  12. }  

在test_util.js脚本中实现onTestCallJs:

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


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

        相关参考:

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

           JSAPI_reference
原创粉丝点击