规则:
js逻辑代码中使用的是jsval类型
计算结果和传递的行参都是RootedValue类型, RootedObject, JSString, Number或其他类型的值都保存在RootedValue类型的变量中。
json是RootedObject类型
数组也是RootedObject类型 用 JS_IsArrayObject 判断是否为数组
数组长度通过JS_GetArrayLength获取
元素通过JS_GetElement获取
js to c++
value.isNumber(),JS::ToNumber()
isObject(),JS_ValueToObject()
v.isString(); JSString *tmp =JS::ToString(cx, v); JSStringWrapper str(tmp); *ret = str.get();
读取json类型值:
bool jsval_to_vector2(JSContext *cx, JS::HandleValue vp/*传入js类型的值, 该值可能是一个js对象或者是一个js变量*/, cocos2d::Vec2* ret/*传出*/) { //创建js对象 JS::RootedObject tmp(cx); //创建js变量 JS::RootedValue jsx(cx); JS::RootedValue jsy(cx); double x, y; bool ok = vp.isObject() &&//vp是否可转为对象 JS_ValueToObject(cx, vp, &tmp) &&//vp转为对象 JS_GetProperty(cx, tmp, "x", &jsx) &&//获取json属性 中的js变量值 JS_GetProperty(cx, tmp, "y", &jsy) && JS::ToNumber(cx, jsx, &x) &&//js变量转C++浮点 JS::ToNumber(cx, jsy, &y); JSB_PRECONDITION3(ok, cx, false, "Error processing arguments"); ret->x = (float)x;//赋值 ret->y = (float)y; return true; }读取js数组:
bool jsval_to_std_vector_int( JSContext *cx, JS::HandleValue vp, std::vector<int>* ret) { //创建js 对象 JS::RootedObject jsobj(cx); //如果能转为对象 则转为对象 计算结果得到的都是RootedValue, RootedObject, JSString, Number 或其他类型的值都保存在RootedValue中 bool ok = vp.isObject() && JS_ValueToObject( cx, vp, &jsobj ); JSB_PRECONDITION3( ok, cx, false, "Error converting value to object"); JSB_PRECONDITION3( jsobj && JS_IsArrayObject( cx, jsobj), cx, false, "Object must be an array"); uint32_t len = 0; //获取对象的数组长度 JS_GetArrayLength(cx, jsobj, &len); for (uint32_t i=0; i < len; i++) { //创建js类型变量 JS::RootedValue value(cx); if (JS_GetElement(cx, jsobj, i, &value)) { if (value.isNumber()) { double number = 0.0; //转类型 ok = JS::ToNumber(cx, value, &number); if (ok) { ret->push_back(static_cast<int>(number)); } } else { JS_ReportError(cx, "not supported type in array"); return false; } } } return true; }
c++ to js
如果是 obj JS_NewObject JS_DefineProperty OBJECT_TO_JSVAL
如果是Array JS_NewArrayObject JS_SetElement OBJECT_TO_JSVAL
int32_to_jsval
std_string_to_jsval
创建json类型值:
jsval vector2_to_jsval(JSContext *cx, const cocos2d::Vec2& v) { //创建一个js对象 JS::RootedObject proto(cx); JS::RootedObject parent(cx); JS::RootedObject tmp(cx, JS_NewObject(cx, NULL, proto, parent)); if (!tmp) return JSVAL_NULL; //定义对象的属性x和y bool ok = JS_DefineProperty(cx, tmp, "x", v.x, JSPROP_ENUMERATE | JSPROP_PERMANENT) && JS_DefineProperty(cx, tmp, "y", v.y, JSPROP_ENUMERATE | JSPROP_PERMANENT); if (ok) { //返回一个jsval值 return OBJECT_TO_JSVAL(tmp); } return JSVAL_NULL; }
创建一个js数组
jsval std_vector_int_to_jsval( JSContext *cx, const std::vector<int>& v) { JS::RootedObject jsretArr(cx, JS_NewArrayObject(cx, 0)); int i = 0; for (const int obj : v) { JS::RootedValue arrElement(cx); arrElement = int32_to_jsval(cx, obj); if (!JS_SetElement(cx, jsretArr, i, arrElement)) { break; } ++i; } return OBJECT_TO_JSVAL(jsretArr); }
// // jsb_kenko_auto.h // Fishing2d36JSB // // Created by TinyUlt on 11/16/15. // // #ifndef jsb_jsb_kenko_auto_h #define jsb_jsb_kenko_auto_h #include "cocos2d.h" #include "jsapi.h" #include "jsfriendapi.h" std::string os_info(); bool jsb_os_info(JSContext *cx, uint32_t argc, JS::Value *vp); bool jsb_callback(JSContext *cx, uint32_t argc, JS::Value *vp); void register_jsb_kenko_all(JSContext* cx, JS::HandleObject obj); #endif
// // jsb_kenko_auto.cpp // Fishing2d36JSB // // Created by TinyUlt on 11/16/15. // // #include "jsb_kenko_auto.h" #include "cocos2d_specifics.hpp" std::string os_info() { CCLOG("it's c++ os_info here"); return "os_info"; } bool jsb_os_info(JSContext *cx, uint32_t argc, JS::Value *vp) { JS::CallArgs args = JS::CallArgsFromVp(argc, vp); if (argc == 0) { std::string ret = os_info(); jsval jsret = JSVAL_NULL; jsret = std_string_to_jsval(cx, ret); args.rval().set(jsret); return true; } JS_ReportError(cx, "js_FishAlg_FishAlg_getOutRotation3D : wrong number of arguments: %d, was expecting %d", argc, 0); return false; } bool jsb_callback(JSContext *cx, uint32_t argc, JS::Value *vp) { CCLOG("it's c++ testCallback here"); JSContext* jc = ScriptingCore::getInstance()->getGlobalContext(); // 注释部分适合有对象化的调用 // 参考:http://www.tairan.com/archives/4902 //jsval v[2]; //v[0] = int32_to_jsval(jc, 32); //v[1] = int32_to_jsval(jc, 12); // 通过 ScriptingCore 封装好的方法实现回调,可以帮助我们节省很多细节上的研究 //js_proxy_t * p = jsb_get_native_proxy(); //return ScriptingCore::getInstance()->executeFunctionWithOwner(OBJECT_TO_JSVAL(p->obj), "cpp_callback", 2, v); //2是参数个数,v是参数列表 //找到一个更适合全局函数的方法 jsval ret; return ScriptingCore::getInstance()->evalString("cpp_callback(2,3)", &ret); } void register_jsb_kenko_all(JSContext *cx, JS::HandleObject obj) { JS_DefineFunction(cx, obj, "os_Info", jsb_os_info, 0, 0); //生成名为osInfo的js全局函数 JS_DefineFunction(cx, obj, "test_cpp_callback", jsb_callback, 0, 0); // JS_DefineFunction(cx, tmpObj, "getInstance", js_PlistParser_getInstance, 0, JSPROP_READONLY | JSPROP_PERMANENT); }
function cpp_callback(a, b) { cc.log("cpp return two integer: " + a + " " + b); }
cc.log("js get from c++: " + os_Info()); test_cpp_callback();
// // Network.h // cocos2d_libs // // Created by TinyUlt on 11/16/15. // // #ifndef __cocos2d_libs__Network__ #define __cocos2d_libs__Network__ #include <stdio.h> class Network{ public: Network(); ~Network(); bool OnMessage(); }; #endif /* defined(__cocos2d_libs__Network__) */
// // Network.cpp // cocos2d_libs // // Created by TinyUlt on 11/16/15. // // #include "Network.h" #include "cocos2d.h" #include "jsapi.h" #include "jsfriendapi.h" #include "cocos2d_specifics.hpp" Network::Network(){ } Network::~Network(){ } bool Network::OnMessage(){ js_proxy_t * p = jsb_get_native_proxy(this); jsval retval; JSContext* jc = ScriptingCore::getInstance()->getGlobalContext(); // 定义参数,由两个参数 jsval v[] = { v[0] = int32_to_jsval(jc, 32), v[1] =UINT_TO_JSVAL(88) }; // 通过 ScriptingCore 封装好的方法实现回调,可以帮助我们节省很多细节上的研究 ScriptingCore::getInstance()->executeFunctionWithOwner(OBJECT_TO_JSVAL(p->obj), "callback", 2, v); return true; }
network.callback = function (i, j) { log("network.callback " + i + j); } network.OnMessage();
// // jsb_JS_APP_CB.hpp // cocos2d_js_bindings // // Created by TinyUlt on 1/9/16. // // #ifndef jsb_JS_APP_CB_hpp #define jsb_JS_APP_CB_hpp #include "jsapi.h" #include "jsfriendapi.h" void register_all_js_cpp_cb(JSContext* cx, JS::HandleObject global); #endif /* jsb_JS_APP_CB_hpp */
// // jsb_JS_APP_CB.cpp // cocos2d_js_bindings // // Created by TinyUlt on 1/9/16. // // #include "jsb_JS_APP_CB.hpp" #if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID || CC_TARGET_PLATFORM == CC_PLATFORM_IOS || CC_TARGET_PLATFORM == CC_PLATFORM_WIN32) #include "ScriptingCore.h" #include "cocos2d_specifics.hpp" #include "jsb_TinyJSWork.hpp" #include "TinyJSWork.h" using namespace cocos2d; static bool jsb_applyStorePay(JSContext *cx, uint32_t argc, jsval *vp) { JSObject *obj = JS_THIS_OBJECT(cx, vp); js_proxy_t *proxy = jsb_get_js_proxy(obj); TinyJSWork* cobj = (TinyJSWork *)(proxy ? proxy->ptr : NULL); JSB_PRECONDITION2( cobj, cx, false, "Invalid Native Object"); if(true){ JS::CallArgs args = JS::CallArgsFromVp(argc, vp); int _type; jsval_to_int32(cx, args.get(0), &_type); int _proID; jsval_to_int32(cx, args.get(1), &_proID); int _gameID; jsval_to_int32(cx, args.get(2), &_gameID); std::shared_ptr<JSFunctionWrapper> func(new JSFunctionWrapper(cx, obj, args.get(3))); cobj->applyStorePay((PurchasePlatform)_type, (ProductID)_proID, _gameID,[=](int purType, int proID, int gameID,bool paySuc)->bool{ Director::getInstance()->getScheduler()->performFunctionInCocosThread([=] { JSB_AUTOCOMPARTMENT_WITH_GLOBAL_OBJCET jsval arg[4]; arg[0] = int32_to_jsval(cx, purType); arg[1] = int32_to_jsval(cx, proID); arg[2] = int32_to_jsval(cx, gameID); arg[3] = bool_to_jsval(cx, paySuc); JS::RootedValue rval(cx); CCLOG("执行js中的 applyStorePay 设置的回调函数"); bool ok = func->invoke(4, arg, &rval); if (!ok && JS_IsExceptionPending(cx)) { JS_ReportPendingException(cx); } }); return true; }); return true; } } extern JSObject* jsb_TinyJSWork_prototype; void register_all_js_cpp_cb(JSContext* cx, JS::HandleObject global) { JS_DefineFunction(cx, JS::RootedObject(cx, jsb_TinyJSWork_prototype), "applyStorePay", jsb_applyStorePay, 4, JSPROP_ENUMERATE | JSPROP_PERMANENT); } #endif
typedef void TinyJSStoreCallback(int purType, int proID, int gameID,bool paySuc); //支付接口 void applyStorePay(PurchasePlatform type, ProductID proID,int gameID, std::function<TinyJSStoreCallback> jsCallback);
测试1
void SwimAlg::test1(){ }
bool js_SwimAlg_SwimAlg_test1(JSContext *cx, uint32_t argc/*形参个数*/, jsval *vp) { //得到参数数组 JS::CallArgs args = JS::CallArgsFromVp(argc, vp); //js对象转化为c++对象 JS::RootedObject obj(cx, args.thisv().toObjectOrNull()); js_proxy_t *proxy = jsb_get_js_proxy(obj); SwimAlg* cobj = (SwimAlg *)(proxy ? proxy->ptr : NULL); //如果不为对象,则报错 JSB_PRECONDITION2( cobj, cx, false, "js_SwimAlg_SwimAlg_test1 : Invalid Native Object"); /// //如果参数个数为0 if (argc == 0) { //执行c++函数 cobj->test1(); //设置返回类型为未定义的 args.rval().setUndefined(); return true; } //如果传入的行参不等于0 则报错 JS_ReportError(cx, "js_SwimAlg_SwimAlg_test1 : wrong number of arguments: %d, was expecting %d", argc, 0); return false; }
测试2
void SwimAlg::test2(int i){ }
bool js_SwimAlg_SwimAlg_test2(JSContext *cx, uint32_t argc, jsval *vp) { JS::CallArgs args = JS::CallArgsFromVp(argc, vp); bool ok = true; JS::RootedObject obj(cx, args.thisv().toObjectOrNull()); js_proxy_t *proxy = jsb_get_js_proxy(obj); SwimAlg* cobj = (SwimAlg *)(proxy ? proxy->ptr : NULL); JSB_PRECONDITION2( cobj, cx, false, "js_SwimAlg_SwimAlg_test2 : Invalid Native Object"); //如果参数有1个 if (argc == 1) { int arg0; //js的整型转c++整型 ok &= jsval_to_int32(cx, args.get(0), (int32_t *)&arg0); JSB_PRECONDITION2(ok, cx, false, "js_SwimAlg_SwimAlg_test2 : Error processing arguments"); //传入参数 cobj->test2(arg0); args.rval().setUndefined(); return true; } JS_ReportError(cx, "js_SwimAlg_SwimAlg_test2 : wrong number of arguments: %d, was expecting %d", argc, 1); return false; }
void SwimAlg::test3(int i, float f){ }
bool js_SwimAlg_SwimAlg_test3(JSContext *cx, uint32_t argc, jsval *vp) { JS::CallArgs args = JS::CallArgsFromVp(argc, vp); bool ok = true; JS::RootedObject obj(cx, args.thisv().toObjectOrNull()); js_proxy_t *proxy = jsb_get_js_proxy(obj); SwimAlg* cobj = (SwimAlg *)(proxy ? proxy->ptr : NULL); JSB_PRECONDITION2( cobj, cx, false, "js_SwimAlg_SwimAlg_test3 : Invalid Native Object"); //如果参数有2个 if (argc == 2) { int arg0; double arg1; ok &= jsval_to_int32(cx, args.get(0), (int32_t *)&arg0); //js数字类型转c++浮点型 ok &= JS::ToNumber( cx, args.get(1), &arg1) && !isnan(arg1); JSB_PRECONDITION2(ok, cx, false, "js_SwimAlg_SwimAlg_test3 : Error processing arguments"); cobj->test3(arg0, arg1); args.rval().setUndefined(); return true; } JS_ReportError(cx, "js_SwimAlg_SwimAlg_test3 : wrong number of arguments: %d, was expecting %d", argc, 2); return false; }
void SwimAlg::test4(double d, Vec2 v){ }
bool js_SwimAlg_SwimAlg_test4(JSContext *cx, uint32_t argc, jsval *vp) { JS::CallArgs args = JS::CallArgsFromVp(argc, vp); bool ok = true; JS::RootedObject obj(cx, args.thisv().toObjectOrNull()); js_proxy_t *proxy = jsb_get_js_proxy(obj); SwimAlg* cobj = (SwimAlg *)(proxy ? proxy->ptr : NULL); JSB_PRECONDITION2( cobj, cx, false, "js_SwimAlg_SwimAlg_test4 : Invalid Native Object"); if (argc == 2) { double arg0; cocos2d::Vec2 arg1; ok &= JS::ToNumber( cx, args.get(0), &arg0) && !isnan(arg0); //js cc.p()类型转 c++ Vec2() 类型 ok &= jsval_to_vector2(cx, args.get(1), &arg1); JSB_PRECONDITION2(ok, cx, false, "js_SwimAlg_SwimAlg_test4 : Error processing arguments"); cobj->test4(arg0, arg1); args.rval().setUndefined(); return true; } JS_ReportError(cx, "js_SwimAlg_SwimAlg_test4 : wrong number of arguments: %d, was expecting %d", argc, 2); return false; }
bool jsval_to_vector2(JSContext *cx, JS::HandleValue vp/*传入js类型的值, 该值可能是一个js对象或者是一个js变量*/, cocos2d::Vec2* ret/*传出*/) { //创建js对象 JS::RootedObject tmp(cx); //创建js变量 JS::RootedValue jsx(cx); JS::RootedValue jsy(cx); double x, y; bool ok = vp.isObject() &&//vp是否可转为对象 JS_ValueToObject(cx, vp, &tmp) &&//vp转为对象 JS_GetProperty(cx, tmp, "x", &jsx) &&//获取json属性 中的js变量值 JS_GetProperty(cx, tmp, "y", &jsy) && JS::ToNumber(cx, jsx, &x) &&//js变量转C++浮点 JS::ToNumber(cx, jsy, &y); JSB_PRECONDITION3(ok, cx, false, "Error processing arguments"); ret->x = (float)x;//赋值 ret->y = (float)y; return true; }
测试5
int SwimAlg::test5(){ return 0; }
bool js_SwimAlg_SwimAlg_test5(JSContext *cx, uint32_t argc, jsval *vp) { JS::CallArgs args = JS::CallArgsFromVp(argc, vp); JS::RootedObject obj(cx, args.thisv().toObjectOrNull()); js_proxy_t *proxy = jsb_get_js_proxy(obj); SwimAlg* cobj = (SwimAlg *)(proxy ? proxy->ptr : NULL); JSB_PRECONDITION2( cobj, cx, false, "js_SwimAlg_SwimAlg_test5 : Invalid Native Object"); if (argc == 0) { //得到返回值 int ret = cobj->test5(); //c++整型转js数值 jsval jsret = JSVAL_NULL; jsret = int32_to_jsval(cx, ret); //设置返回值 args.rval().set(jsret); return true; } JS_ReportError(cx, "js_SwimAlg_SwimAlg_test5 : wrong number of arguments: %d, was expecting %d", argc, 0); return false; }
Vec2 SwimAlg::test6(){ return Vec2::ZERO; }
bool js_SwimAlg_SwimAlg_test6(JSContext *cx, uint32_t argc, jsval *vp) { JS::CallArgs args = JS::CallArgsFromVp(argc, vp); JS::RootedObject obj(cx, args.thisv().toObjectOrNull()); js_proxy_t *proxy = jsb_get_js_proxy(obj); SwimAlg* cobj = (SwimAlg *)(proxy ? proxy->ptr : NULL); JSB_PRECONDITION2( cobj, cx, false, "js_SwimAlg_SwimAlg_test6 : Invalid Native Object"); if (argc == 0) { cocos2d::Vec2 ret = cobj->test6(); jsval jsret = JSVAL_NULL; //Vec2转cc.p(); jsret = vector2_to_jsval(cx, ret); //设置返回值 args.rval().set(jsret); return true; } JS_ReportError(cx, "js_SwimAlg_SwimAlg_test6 : wrong number of arguments: %d, was expecting %d", argc, 0); return false; }
jsval vector2_to_jsval(JSContext *cx, const cocos2d::Vec2& v) { //创建一个js对象 JS::RootedObject proto(cx); JS::RootedObject parent(cx); JS::RootedObject tmp(cx, JS_NewObject(cx, NULL, proto, parent)); if (!tmp) return JSVAL_NULL; //定义对象的属性x和y bool ok = JS_DefineProperty(cx, tmp, "x", v.x, JSPROP_ENUMERATE | JSPROP_PERMANENT) && JS_DefineProperty(cx, tmp, "y", v.y, JSPROP_ENUMERATE | JSPROP_PERMANENT); if (ok) { //返回一个jsval值 return OBJECT_TO_JSVAL(tmp); } return JSVAL_NULL; }
测试7
void SwimAlg::test7(std::vector<int> v){ }
bool jsval_to_std_vector_int( JSContext *cx, JS::HandleValue vp, std::vector<int>* ret) { //创建js 对象 JS::RootedObject jsobj(cx); //如果能转为对象 则转为对象 计算结果得到的都是RootedValue, RootedObject, JSString, Number 或其他类型的值都保存在RootedValue中 bool ok = vp.isObject() && JS_ValueToObject( cx, vp, &jsobj ); JSB_PRECONDITION3( ok, cx, false, "Error converting value to object"); JSB_PRECONDITION3( jsobj && JS_IsArrayObject( cx, jsobj), cx, false, "Object must be an array"); uint32_t len = 0; //获取对象的数组长度 JS_GetArrayLength(cx, jsobj, &len); for (uint32_t i=0; i < len; i++) { //创建js类型变量 JS::RootedValue value(cx); if (JS_GetElement(cx, jsobj, i, &value)) { if (value.isNumber()) { double number = 0.0; //转类型 ok = JS::ToNumber(cx, value, &number); if (ok) { ret->push_back(static_cast<int>(number)); } } else { JS_ReportError(cx, "not supported type in array"); return false; } } } return true; }
测试8
void SwimAlg::test8(std::vector<Vec2> v){ }
bool js_SwimAlg_SwimAlg_test8(JSContext *cx, uint32_t argc, jsval *vp) { JS::CallArgs args = JS::CallArgsFromVp(argc, vp); bool ok = true; JS::RootedObject obj(cx, args.thisv().toObjectOrNull()); js_proxy_t *proxy = jsb_get_js_proxy(obj); SwimAlg* cobj = (SwimAlg *)(proxy ? proxy->ptr : NULL); JSB_PRECONDITION2( cobj, cx, false, "js_SwimAlg_SwimAlg_test8 : Invalid Native Object"); if (argc == 1) { std::vector<cocos2d::Vec2> arg0; ok &= jsval_to_std_vector_ccvec2(cx, args.get(0), &arg0); JSB_PRECONDITION2(ok, cx, false, "js_SwimAlg_SwimAlg_test8 : Error processing arguments"); cobj->test8(arg0); args.rval().setUndefined(); return true; } JS_ReportError(cx, "js_SwimAlg_SwimAlg_test8 : wrong number of arguments: %d, was expecting %d", argc, 1); return false; }