近期工作中由于服务器使用的框架是nodejs,便有了前后端共用同一份js脚本的需求.
网上翻了翻不是老旧的2.x版本就是一些js调用c++的.于是自己动手搞定.这里把完整的过程分享给大家.
首先要确保使用cocos创建了lua工程,并编译通过,可以打apk包。
由于创建的lua工程,并不包含js模块,所以要从引擎中,手动拷贝js模块到frameworks中。
拷贝cocos2d-x-3.8\cocos\scripting\js-bindings到frameworks\cocos2d-x\cocos\scripting
拷贝cocos2d-x-3.8\external\spidermonkey到frameworks\cocos2d-x\external
Win7添加工程依赖工程
VS解决方案添加现有项
然后右键解决方案->属性->通用性->项目依赖->勾上libjscocos2d

添加项目包含目录
项目>属性->配置属性->C+±>常规->附加包含目录
(EngineRoot)cocos\base
(EngineRoot)external\spidermonkey\include\win32
$(EngineRoot)cocos\scripting\js-bindings\manual
添加依赖项
项目>属性->配置属性->连接器->输入->附加依赖项
mozjs-33.lib
ws2_32.lib
sqlite3.lib
android的话比较容易只需要修改android.mk文件就好
添加静态库
LOCAL_STATIC_LIBRARIES += cocos2d_js_static
添加库路径
$(call import-module,scripting/js-bindings/proj.android) \
在ScriptCore.ccp中,可以注释掉以下行.免得老抛警告
//runScript(“script/jsb_prepare.js”);
接下来就是上代码了.
JSScriptBind.h文件
#pragma once
#include “ScriptingCore.h”
#include “cocos2d.h”
USING_NS_CC;
extern “C”{
#include “lua.h”
int luaopen_JSScriptBind(lua_State *L);
};
JSScriptBind.cpp文件
#include “JSScriptBind.h”
//公用数据
static ScriptingCore* g_sc = nullptr;
const int MAX_ARGC = 10;
static jsval g_Argv;
static int g_Argc = 0;
static int initJSScriptBind(lua_State *L)
{
g_sc = ScriptingCore::getInstance();
g_sc->start();
return 0;
}
static int jsbRunScript(lua_State *L)
{
std::string path = lua_tostring(L, 1);
g_sc->runScript(CCFileUtils::getInstance()->fullPathForFilename(path).c_str());
return 0;
}
static int jsbCallFunction(lua_State *L)
{
std::string funcName = lua_tostring(L, 1);
JSContext *cx = g_sc->getGlobalContext();
JS::RootedValue retval(cx);
g_sc->executeFunctionWithOwner(OBJECT_TO_JSVAL(g_sc->getGlobalObject()), funcName.c_str(), g_Argc, g_Argv, &retval);
g_Argc = 0;
uint32_t length = 1;
if ((&retval)->isNumber())
{
double value = retval.toNumber();
lua_pushnumber(L, value);
}
else if((&retval)->isInt32())
{
int value = retval.toInt32();
lua_pushnumber(L, value);
}
else if((&retval)->isDouble())
{
double value = retval.toDouble();
lua_pushnumber(L, value);
}
else if((&retval)->isString())
{
JSStringWrapper jstrw(retval.toString());
std::string value = jstrw.get();
lua_pushlstring(L, value.c_str(), value.length());
}
else if ((&retval)->isMarkable())
{
JS::RootedObject jsobj(cx);
jsobj = retval.toObjectOrNull();
JS_GetArrayLength(cx, jsobj, &length);
for( uint32_t i=0; i<length;i++ )
{
JS::RootedValue valarg(cx);
JS_GetElement(cx, jsobj, i, &valarg);
if ((&valarg)->isNumber())
{
double value = valarg.toNumber();
lua_pushnumber(L, value);
}
else if((&valarg)->isInt32())
{
int value = valarg.toInt32();
lua_pushnumber(L, value);
}
else if((&valarg)->isDouble())
{
double value = valarg.toDouble();
lua_pushnumber(L, value);
}
else if((&valarg)->isString())
{
JSStringWrapper jstrw(valarg.toString());
std::string value = jstrw.get();
lua_pushlstring(L, value.c_str(), value.length());
}
}
}
return length;
}
static int jsbPushNumber(lua_State *L)
{
int i = lua_tonumber(L, 1);
g_Argv = INT_TO_JSVAL(i);
return 0;
}
static int jsbPushString(lua_State L)
{
std::string str = lua_tostring(L, 1);
JSContext cx = g_sc->getGlobalContext();
JSString *jstr = JS_NewStringCopyZ(cx, str.c_str());
g_Argv = STRING_TO_JSVAL(jstr);
return 0;
}
extern “C” {
int luaopen_JSScriptBind(lua_State *L)
{
lua_register(L, “initJSScriptBind”, initJSScriptBind);
lua_register(L, “jsbRunScript”, jsbRunScript);
lua_register(L, “jsbCallFunction”, jsbCallFunction);
lua_register(L, “jsbPushNumber”, jsbPushNumber);
lua_register(L, “jsbPushString”, jsbPushString);
return 0;
}
}
在AppDelegate.pp中.
调用luaopen_JSScriptBind(L); 注册C++方法到lua.
接下来就可以在lua代码中调用js脚本啦。目前这套方案做的比较简单,只支持调用js的全局方法.
写一个简单的js代码进行测试:

Lua中调用:
initJSScriptBind() (只用调用1次)
jsbRunScript(“script/test.js”)
jsbPushNumber(1)
local value = jsbCallFunction(“testFunction”)
大功告成~
接口什么的按照自己的需求去封装就好了。

