如何将c++绑定至javascript 如何在C++程序中嵌入JavaScript脚本语言

\u5982\u4f55\u5728C++\u4e2d\u589e\u52a0\u7ed9JavaScript\u8c03\u7528\u7684API

\u3000\u3000\u53ef\u4ee5\u5728\u5730\u5740\u680f\u4e2d\u8f93\u5165chrome://extensions\u67e5\u770b\u5df2\u5b89\u88c5\u7684\u6269\u5c55\u7a0b\u5e8f\u3002\u4e0b\u56fe\u793a\u4f8b\u8bf4\u660e\u4e86\u6211\u7684\u6d4f\u89c8\u5668\u4e2d\u5df2\u5b89\u88c5\u4e86Google Mail Checker\u6269\u5c55\u7a0b\u5e8f\uff0c\u6211\u4eec\u5c06\u4f7f\u7528\u5b83\u6765\u6d4b\u8bd5\u65b0\u589e\u7684API\uff08\u6d4b\u8bd5\u53ef\u4ee5\u4f7f\u7528\u4efb\u4f55\u6269\u5c55\u7a0b\u5e8f\uff0c\u800c\u4e0d\u9700\u6307\u5b9a\u8fd9\u6240\u793a\u4f8b\u7684Google Mail checker\uff09\u3002

\u3000\u3000\u4ece\u4e0a\u56fe\u4e5f\u540c\u65f6\u793a\u4f8b\u4e86\u5982\u4f55\u6253\u5f00Chrome\u7f51\u4e0a\u5546\u5e97\uff0c\u6211\u4eec\u9700\u8981\u8fdb\u5165\u8be5\u9875\u9762\u67e5\u770b\u5df2\u5f00\u53d1\u597d\u7684API\u3002\u8fdb\u5165\u9875\u9762\u540e\u6309F12\u6253\u5f00\u5f00\u53d1\u8005\u5de5\u5177\uff0c\u5e76\u5c06\u5f00\u53d1\u8005\u5de5\u5177\u5207\u6362\u5230\u63a7\u5236\u53f0\u3002


\u3000\u3000\u5728\u5f00\u53d1\u8005\u5de5\u5177\u7684\u63a7\u5236\u53f0\u4e2d\uff0c\u8f93\u5165\u201cchrome.management.un\u201d\u5176\u5c06\u663e\u793amanagement namespace\u6240\u652f\u6301\u7684API\u3002


\u3000\u3000\u4e0b\u9762\u6211\u4eec\u8981\u505a\u7684\uff0c\u5c31\u662f\u5728management\u4e2d\u589e\u52a0showButton API\uff0c\u7528\u4e8e\u663e\u793a\u6216\u9690\u85cf\u6269\u5c55\u680f\u4e0a\uff08\u67d0\uff09\u6269\u5c55\u7a0b\u5e8f\u7684Icon\u3002\u589e\u52a0showButton API\u5927\u4f53\u4e0a\u5206\u6210\u4e24\u5927\u90e8\u9aa4\u3002\u6b65\u9aa4\u4e00\u4e3a\u53d8\u66f4C++\u4ee3\u7801\uff0c\u6b65\u9aa4\u4e8c\u4e3a\u53d8\u66f4management.json\u63a5\u53e3\u63cf\u8ff0\u6587\u4ef6\u3002\u4e0b\u9762\u9010\u6b65\u8bb2\u89e3\u57fa\u4e8eChrome R28\u6e90\u7801\u7684\u5177\u4f53\u53d8\u66f4\u5185\u5bb9\u3002

\u3000\u3000\u9996\u5148\uff0c\u5728src\chrome\browser\extensions\api\management\management_api.h\u4e2d\u589e\u52a0\u4e00\u4e2a\u65b0\u7c7b\u7684\u58f0\u660e\u3002\u5f53showButton\u5728Javascript\u4e2d\u88ab\u8c03\u7528\u65f6\uff0c\u8be5\u7c7b\u5c06\u8d1f\u8d23\u8fdb\u884c\u540e\u7eed\u5904\u7406\uff0c\u5176RunImpl\u65b9\u6cd5\u5c06\u4f1a\u88ab\u8c03\u7528\u3002

\u3000\u3000
\u3000\u3000
\u3000\u3000class ManagementShowButtonFunction : public ManagementFunction {
\u3000\u3000public:
\u3000\u3000DECLARE_EXTENSION_FUNCTION("management.showButton", MANAGEMENT_UNINSTALL)
\u3000\u3000private:
\u3000\u3000virtual bool RunImpl() OVERRIDE;
\u3000\u3000};
\u3000\u3000

\u3000\u3000\u63a5\u7740\uff0c\u5728src\chrome\browser\extensions\api\management\management_api.cc\u4e2d\u589e\u52a0\u65b0\u7c7b\u7684\u5b9e\u73b0\u3002RunImpl\u65b9\u6cd5\u6839\u636eJavaScript\u6240\u4f20\u5165\u7684\u4e24\u4e2a\u53c2\u6570\u8c03\u7528SetBrowserActionVisibility\u51fd\u6570\uff0c\u5b9e\u73b0\u5bf9\u6269\u5c55\u7a0b\u5e8fIcon\u7684\u663e\u793a\u548c\u9690\u85cf\u3002\u7b2c\u4e00\u4e2a\u53c2\u6570\u4e3a\u6269\u5c55\u7a0b\u5e8f\u7684ID\uff0c\u7b2c\u4e8c\u4e2a\u53c2\u6570\u662f\u4e00\u4e2a\u5e03\u5c14\u53d8\u91cf\uff0c\u7528\u4e8e\u6307\u793a\u662f\u663e\u793a\uff08true\uff09\u6291\u6216\u9690\u85cf\uff08false\uff09\u6269\u5c55\u7a0b\u5e8f\u7684Icon\u3002


\u3000\u3000\u6709\u4e86\u4ee5\u4e0a\u7684\u53d8\u66f4\u540e\uff0c\u5728\u7f16\u8bd1Chrome\u9879\u76ee\u4e4b\u524d\uff0c\u9700\u624b\u52a8\u91cd\u65b0\u7f16\u8bd1api\u9879\u76ee\uff0c\u56e0\u4e3aChrome\u9879\u76ee\u5e76\u4e0d\u4f9d\u8d56\u4e8eapi\u9879\u76ee\u3002\u91cd\u65b0\u7f16\u8bd1\u5c06\u4f7f\u5f97\u5728\u81ea\u52a8\u751f\u6210\u7684GeneratedFunctionRegistry:: RegisterAll\u51fd\u6570\u5185\u589e\u52a0\u5bf9ManagementShowButtonFunction\u7684\u6ce8\u518c\u3002


\u3000\u3000\u7a0b\u5e8f\u7f16\u8bd1\u5b8c\u6210\u540e\uff0c\u6211\u4eec\u53ef\u4ee5\u5728\u5f00\u53d1\u8005\u5de5\u5177\u7684\u63a7\u5236\u53f0\u4e0a\u6d4b\u8bd5showButton\u51fd\u6570\u3002\u4e0b\u56fe\u793a\u4f8b\u8bf4\u660e\u4e86\u901a\u8fc7\u8c03\u7528\u8be5\u51fd\u6570\u9690\u85cf\u548c\u663e\u793aGoogle Mail Checker\u6269\u5c55\u7a0b\u5e8f\u7684Icon\u3002


\u3000\u3000\u4e0a\u9762\u793a\u4f8b\u4e86\u5982\u4f55\u5728\u5df2\u5b58\u5728\u7684management namespace\u4e2d\u589e\u52a0\u4e00\u4e2aAPI\u3002\u5728Chrome\u4e2d\uff0cJavaScript API\u7684\u4f7f\u7528\u5b58\u5728\u6743\u9650\u7684\u6982\u5ff5\u3002\u5982\u679c\u65b0\u589eAPI\u7684\u540c\u65f6\u4e5f\u9700\u65b0\u589enamespace\u7684\u8bdd\uff0c\u9700\u8981\u6ce8\u610f\u5728APIPermissionInfo::RegisterAllPermissions\u65b9\u6cd5\u4e2d\u6ce8\u518c\u65b0\u589enamespace\u7684\u6743\u9650\uff0c\u5426\u5219\u4f1a\u51fa\u73b0\u9875\u9762\u65e0\u6cd5\u8bbf\u95ee\u65b0\u589eAPI\u7684\u95ee\u9898\u3002

\u60f3\u60f3IE\u6d4f\u89c8\u5668\u4e3a\u4ec0\u4e48\u80fd\u6267\u884c\u7f51\u9875\u4e2d\u7684JavaScript\u811a\u672c\uff0cIE\u4e0d\u4e5f\u662f\u4e2a\u7a0b\u5e8f\u5417\uff1f\u56e0\u4e3aIE\u5185\u7f6e\u4e86\u4e00\u4e2aJavaScript\u5f15\u64ce(\u5373\u4e00\u4e2aJavaScript\u89e3\u91ca\u7a0b\u5e8f)\u3002\u540c\u7406\uff0c\u60f3\u8981\u4f60\u81ea\u5df1\u5199\u7684C++\u7a0b\u5e8f\u4e5f\u80fd\u6267\u884cJavaScript\u811a\u672c\uff0c\u5728\u4f60\u7684\u7a0b\u5e8f\u4e2d\u4e5f\u5e94\u8be5\u5305\u542b\u4e00\u4e2a\u8fd9\u6837\u7684\u5f15\u64ce\u3002\u5b83\u53ef\u4ee5\u4ee5\u63d2\u4ef6\u7684\u5f62\u5f0f\u63d0\u4f9b\uff0c\u7f51\u4e0a\u53ef\u80fd\u63d0\u4f9b\u4e86\u8fd9\u6837\u7684\u63d2\u4ef6\u4e0b\u8f7d\u6216\u63d2\u4ef6\u7684\u6e90\u7801\uff0c\u5426\u5219\uff0c\u81ea\u5df1\u5199\u8d77\u6765\u53ef\u4e0d\u5bb9\u6613\u3002

下载绑定生成器,本机路径/Users/iven/Dev/bindings-generator
为了在Mac OS X中安装运行MacPort端口,系统必须要已经安装苹果的“Command Line Developer Tools”(命令行开发者工具)。Xcode 4及以后版本的用户首先需要通过启动或运行Xcode接受Xcode EULA。

xcodebuild -license
下载安装MacPort
注意:如果是Homebrew用户,应该先卸载Homebrew。因为Homebrew不兼容MacPort。
同时执行MacPort的“selfupdate”命令以确保安装最新的发布版本。

sudo port -v selfupdate
当更新完成之后,使用MacPort在命令行中安装python依赖(dependencies)

sudo port install python27 py27-yaml py27-cheetah
你会看到如下所示:

下载llvm-3.3,解压至$HOME/bin目录。如果没有bin目录,请创建一个bin目录,将未解压的ZIP压缩包重命名为“clang+llvm-3.3”。
最后目录如下所示:/Users/guanghui/bin/clang+llvm-3.3(guanhui是本机的主目录名字)

样本代码

绑定生成器资源库中包括一个样本测试用例。打开bindings-generator/test/simple_test文件夹。

配置

根据自己的环境个性化设置“test/userconf.ini”和“test/user.cfg”文件。
注意:应该移除后缀为“.sample”的文件如“user.cfg.sample”和“userconf.ini.sample”

[DEFAULT]
androidndkdir=/Users/iven/Dev/android-ndk-r8c
clangllvmdir=/Users/iven/Dev/clang+llvm-3.1-x86_64-apple-darwin11
cxxgeneratordir=/Users/iven/Dev/bindings-generator-master
user.cfg配置如下所示

PYTHON_BIN=/opt/local/Library/Frameworks/Python.framework/Versions/2.7/bin/ python2.7
运行测试样本

./test.sh
如果环境设置正确,你会看到如下所示:

Errors in parsing headers:
1. <severity = Warning,
location =<SourceLocation file None, line 0, column 0>,
details = "argument unusedduring compilation: '-nostdinc++'">
不用担心这个警告,你已完成运行,测试用例会创建一个包含3个文件的“simple_test_bindings”目录。

一个绑定类的.hpp头文件

一个实现绑定类的.cpp文件

一个介绍如何(从Java脚本)调用C++类暴露方法的.js文件。

运行测试

Create a JS base Cocos2d-x project. 创建基于JS的Cocos2d-x项目

将“simple_Test folder”文件夹和“simple_test_binding”文件夹添加到项目中

修改“autogentestbindings.cpp”中的注册函数如下:

void register_all_autogentestbindings(JSContext* cx, JSObject* obj) {
jsval nsval;
JSObject *ns;
JS_GetProperty(cx, obj, "ts",&nsval);
if (nsval == JSVAL_VOID) {
ns = JS_NewObject(cx, NULL, NULL, NULL);
nsval = OBJECT_TO_JSVAL(ns);
JS_SetProperty(cx, obj, "ts",&nsval);
} else {
JS_ValueToObject(cx,nsval, &ns);
}
obj = ns;
js_register_autogentestbindings_SimpleNativeClass(cx, obj);
}
注意:如果你将“ts”添加到“test.ini”文件中的“target_namespace”变量里,便会自动生成代码。无需修改。

target_namespace =ts
在“AppDelegate”中注册

包含头文件“autogentestbindings.hpp”然后注册回调函数:

sc->addRegisterCallback(register_all_autogentestbindings);
在“hello.js”文件适当地方增加以下代码。本机将“init f”函数放在第一个场景。

var myClass=new ts.SimpleNativeClass();
var myStr=myClass.returnsACString();
var label = cc.LabelTTF.create(myStr, "Helvetica", 20.0);
限制

绑定生成器存在以下两个限制

自变量数字参数无法工作,所以需要手动编写包装器
代表类无法工作,所以需要手动绑定,详见下一部分。
手动 JSB 绑定

本指南将介绍利用Cocos2d-x 2.14模板如何在自己的项目中实现JSB绑定。
首先用Cocos2d-js模板创建项目。其次,我们会介绍如何一步一步从JS调用本地函数。最后你便会学会如何从本地代码调用JS代码了。
现在让我们开始!本机使用的Mac OS X作为开发环境。

步骤1. 用Cocos2dx-js模板创建新项目,同时新建一个即将绑定至JS的C++类。

将项目命名为“JSBinding”然后点击“Next”、“ Create”

新建一个类然后实现这个类,等会再将其绑定至JS。
按“command+N”新建一个C++类并命名为“JSBinding”,路径为“OS X\C and C++\C++ Class”。

将以下代码添加到“JSBinding.h”文件中。

#include "cocos2d.h"
#include "ScriptingCore.h"
// Define a namespace to manage your code and make your code clearly
namespace JSB {
class JSBinding: public cocos2d::CCObject
{
public:
static cocos2d::CCScene* scene();
virtual bool init();
CREATE_FUNC(JSBinding);
void functionTest();
};
}
现在实现JSBinding.cpp中的类。如下所示:

bool JSB::JSBinding::init(){
bool bRef = false;
do{
cocos2d::CCLog("JSB init...");
bRef = true;
} while (0);
return bRef;
}
void JSB::JSBinding::functionTest(){
cocos2d::CCLog("Function test...");
}
步骤2. 将C++代码绑定至Java脚本代码

按“command+N”新建C++类,然后命名“JSB_AUTO”路径“OS X\C and C++\C++ Class”。

往“JSB_AUTO.h”文件中增加一些代码

#include "jsapi.h"
#include "jsfriendapi.h"
#include "ScriptingCore.h"
#include "JSBinding.h"
void register_all(JSContext* cx, JSObject* obj);
然后注意“JSB_AUTO.cpp”的实现。

#include "jsapi.h"
#include "jsfriendapi.h"
#include "ScriptingCore.h"
#include "JSBinding.h"
void register_all(JSContext* cx, JSObject* obj);
然后注意“JSB_AUTO.cpp”的实现。

#include "cocos2d.h"
#include "cocos2d_specifics.hpp"
// Binding specific object by defining JSClass
JSClass* jsb_class;
JSObject* jsb_prototype;
// This function is mapping the function “functionTest” in “JSBinding.cpp”
JSBool js_functionTest(JSContext* cx, uint32_t argc, jsval* vp){
JSBool ok = JS_TRUE;
JSObject* obj = NULL;
JSB::JSBinding* cobj = NULL;
obj = JS_THIS_OBJECT(cx, vp);
js_proxy_t* proxy = jsb_get_js_proxy(obj);
cobj = (JSB::JSBinding* )(proxy ? proxy->ptr : NULL);
JSB_PRECONDITION2(cobj, cx, JS_FALSE, "Invalid Native Object");
if (argc == 0) {
cobj->functionTest();
JS_SET_RVAL(cx, vp, JSVAL_VOID);
return ok;
}
JS_ReportError(cx, "Wrong number of arguments");
return JS_FALSE;
}
JSBool js_constructor(JSContext* cx, uint32_t argc, jsval* vp){
cocos2d::CCLog("JS Constructor...");
if (argc == 0) {
JSB::JSBinding* cobj = new JSB::JSBinding();
cocos2d::CCObject* ccobj = dynamic_cast<cocos2d::CCObject*>(cobj);
if (ccobj) {
ccobj->autorelease();
}
TypeTest<JSB::JSBinding> t;
js_type_class_t* typeClass;
uint32_t typeId = t.s_id();
HASH_FIND_INT(_js_global_type_ht, &typeId, typeClass);
assert(typeClass);
JSObject* obj = JS_NewObject(cx, typeClass->jsclass, typeClass->proto, typeClass->parentProto);
JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(obj));
js_proxy_t* p = jsb_new_proxy(cobj, obj);
JS_AddNamedObjectRoot(cx, &p->obj, "JSB::JSBinding");
return JS_TRUE;
}
JS_ReportError(cx, "Wrong number of arguments: %d, was expecting: %d", argc, 0);
return JS_FALSE;
}
// This function is mapping the function “create” when using JavaScript code
JSBool js_create(JSContext* cx, uint32_t argc, jsval* vp){
cocos2d::CCLog("js is creating...");
if (argc == 0) {
JSB::JSBinding* ret = JSB::JSBinding::create();
jsval jsret;
do{
if (ret) {
js_proxy_t* proxy = js_get_or_create_proxy<JSB::JSBinding>(cx, ret);
jsret = OBJECT_TO_JSVAL(proxy->obj);
}
else{
jsret = JSVAL_NULL;
}
} while(0);
JS_SET_RVAL(cx, vp, jsret);
return JS_FALSE;
}
JS_ReportError(cx, "Wrong number of arguments");
return JS_FALSE;
}
void js_finalize(JSFreeOp* fop, JSObject* obj){
CCLOGINFO("JSBindings: finallizing JS object %p JSB", obj);
}
// Binding JSB type
void js_register(JSContext* cx, JSObject* global){
jsb_class = (JSClass *)calloc(1, sizeof(JSClass));
jsb_class->name = "JSBinding";
jsb_class->addProperty = JS_PropertyStub;
jsb_class->delProperty = JS_PropertyStub;
jsb_class->getProperty = JS_PropertyStub;
jsb_class->setProperty = JS_StrictPropertyStub;
jsb_class->enumerate = JS_EnumerateStub;
jsb_class->resolve = JS_ResolveStub;
jsb_class->convert = JS_ConvertStub;
jsb_class->finalize = js_finalize;
jsb_class->flags = JSCLASS_HAS_RESERVED_SLOTS(2);
static JSPropertySpec properties[] = {
{0, 0, 0, JSOP_NULLWRAPPER, JSOP_NULLWRAPPER}
};
// Binding functionTest function
static JSFunctionSpec funcs[] = {
JS_FN("functionTest", js_functionTest, 1, JSPROP_PERMANENT | JSPROP_ENUMERATE),
JS_FS_END
};
// Binding create() function
static JSFunctionSpec st_funcs[] = {
JS_FN("create", js_create, 0, JSPROP_PERMANENT | JSPROP_ENUMERATE),
JS_FS_END
};
// Binding constructor function and prototype
jsb_prototype = JS_InitClass(
cx, global,
NULL,
jsb_class,
js_constructor, 0,
properties,
funcs,
NULL,
st_funcs);
JSBool found;
JS_SetPropertyAttributes(cx, global, "JSB", JSPROP_ENUMERATE | JSPROP_READONLY, &found);
TypeTest<JSB::JSBinding> t;
js_type_class_t* p;
uint32_t typeId = t.s_id();
HASH_FIND_INT(_js_global_type_ht, &typeId, p);
if (!p) {
p = (js_type_class_t* )malloc(sizeof(_js_global_type_ht));
p->type = typeId;
p->jsclass = jsb_class;
p->proto = jsb_prototype;
p->parentProto = NULL;
HASH_ADD_INT(_js_global_type_ht, type, p);
}
}
// Binding JSB namespace so in JavaScript code JSB namespce can be recognized
void register_all(JSContext* cx, JSObject* obj){
jsval nsval;
JSObject* ns;
JS_GetProperty(cx, obj, "JS", &nsval);
if (nsval == JSVAL_VOID) {
ns = JS_NewObject(cx, NULL, NULL, NULL);
nsval = OBJECT_TO_JSVAL(ns);
JS_SetProperty(cx, obj, "JSB", &nsval);
}
else{
JS_ValueToObject(cx, nsval, &ns);
}
obj = ns;
js_register(cx, obj);
}
现在已经完成了大部分工作,但是我们需要在“SpiderMonkey”进行注册。
打开“AppDelegate.cpp”增加以下代码

ScriptingCore* sc = ScriptingCore::getInstance();
sc->addRegisterCallback(register_all); //add this line
步骤3. 内存管理
在register_all函数前增加两个新函数。

JSBool JSB_cocos2dx_retain(JSContext* cx, uint32_t argc, jsval *vp){
JSObject* thisObj = JS_THIS_OBJECT(cx, vp);
if (thisObj) {
js_proxy_t* proxy = jsb_get_js_proxy(thisObj);
if (proxy) {
((CCObject* )proxy->ptr)->retain();
CCLog("Retain succeed!");
return JS_TRUE;
}
}
JS_ReportError(cx, "Invaild native object");
return JS_FALSE;
}
JSBool JSB_cocos2dx_release(JSContext* cx, uint32_t argc, jsval *vp){
JSObject* thisObj = JS_THIS_OBJECT(cx, vp);
if (thisObj) {
js_proxy_t* proxy = jsb_get_js_proxy(thisObj);
if (proxy) {
((CCObject* )proxy->ptr)->release();
CCLog("Release succeed!");
return JS_TRUE;
}
}
JS_ReportError(cx, "Invaild native object");
return JS_FALSE;
}
在register_all函数中增加以下代码:

JS_DefineFunction(cx, jsb_prototype, "retain", JSB_cocos2dx_retain, 0, JSPROP_READONLY | JSPROP_PERMANENT);
JS_DefineFunction(cx, jsb_prototype, "retain", JSB_cocos2dx_release, 0, JSPROP_READONLY | JSPROP_PERMANENT);
步骤4. 使用C++代码回调Java脚本代码
在C++代码回调Java脚本代码之前增加一些代码至“hello.js”文件。

var testJSB = new JSB.JSBinding();
testJSB.callback = function(i, j){
log("JSB Callback" + i + j);
};
然后打开“JSBinding.cpp”在“functionTest”中增加一些代码。

js_proxy_t* p = jsb_get_native_proxy(this);
jsval retval;
jsval v[] = {
v[0] = UINT_TO_JSVAL(32),
v[1] = UINT_TO_JSVAL(88)
};
ScriptingCore::getInstance()->executeFunctionWithOwner(OBJECT_TO_JSVAL(p->obj),
"callback", 2, v, &retval);
使用“executeFunctionWithOwner()”函数简化函数调用程序
步骤5. 绑定测试
在“hello.js”文件中增加以下代码。

var testJSB = new JSB.JSBinding();
testJSB.retain();
testJSB.functionTest();
testJSB.release();
步骤6. 现在取出(check out)项目
如果你的绑定程序正确无误,将会在调试窗口看到如下界面:

恭喜你成功将JS绑定至本地代码!

下载绑定生成器,本机路径/Users/iven/Dev/bindings-generator
为了在Mac OS X中安装运行MacPort端口,系统必须要已经安装苹果的“Command Line Developer Tools”(命令行开发者工具)。Xcode 4及以后版本的用户首先需要通过启动或运行Xcode接受Xcode EULA。

xcodebuild -license
下载安装MacPort
注意:如果是Homebrew用户,应该先卸载Homebrew。因为Homebrew不兼容MacPort。
同时执行MacPort的“selfupdate”命令以确保安装最新的发布版本。

sudo port -v selfupdate
当更新完成之后,使用MacPort在命令行中安装python依赖(dependencies)

sudo port install python27 py27-yaml py27-cheetah
你会看到如下所示:

下载llvm-3.3,解压至$HOME/bin目录。如果没有bin目录,请创建一个bin目录,将未解压的ZIP压缩包重命名为“clang+llvm-3.3”。
最后目录如下所示:/Users/guanghui/bin/clang+llvm-3.3(guanhui是本机的主目录名字)

样本代码

绑定生成器资源库中包括一个样本测试用例。打开bindings-generator/test/simple_test文件夹。

配置

根据自己的环境个性化设置“test/userconf.ini”和“test/user.cfg”文件。
注意:应该移除后缀为“.sample”的文件如“user.cfg.sample”和“userconf.ini.sample”

[DEFAULT]
androidndkdir=/Users/iven/Dev/android-ndk-r8c
clangllvmdir=/Users/iven/Dev/clang+llvm-3.1-x86_64-apple-darwin11
cxxgeneratordir=/Users/iven/Dev/bindings-generator-master
user.cfg配置如下所示

PYTHON_BIN=/opt/local/Library/Frameworks/Python.framework/Versions/2.7/bin/ python2.7
运行测试样本

./test.sh
如果环境设置正确,你会看到如下所示:

Errors in parsing headers:
1. <severity = Warning,
location =<SourceLocation file None, line 0, column 0>,
details = "argument unusedduring compilation: '-nostdinc++'">
不用担心这个警告,你已完成运行,测试用例会创建一个包含3个文件的“simple_test_bindings”目录。

一个绑定类的.hpp头文件

一个实现绑定类的.cpp文件

一个介绍如何(从Java脚本)调用C++类暴露方法的.js文件。

运行测试

Create a JS base Cocos2d-x project. 创建基于JS的Cocos2d-x项目

将“simple_Test folder”文件夹和“simple_test_binding”文件夹添加到项目中

修改“autogentestbindings.cpp”中的注册函数如下:

void register_all_autogentestbindings(JSContext* cx, JSObject* obj) {
jsval nsval;
JSObject *ns;
JS_GetProperty(cx, obj, "ts",&nsval);
if (nsval == JSVAL_VOID) {
ns = JS_NewObject(cx, NULL, NULL, NULL);
nsval = OBJECT_TO_JSVAL(ns);
JS_SetProperty(cx, obj, "ts",&nsval);
} else {
JS_ValueToObject(cx,nsval, &ns);
}
obj = ns;
js_register_autogentestbindings_SimpleNativeClass(cx, obj);
}
注意:如果你将“ts”添加到“test.ini”文件中的“target_namespace”变量里,便会自动生成代码。无需修改。

target_namespace =ts
在“AppDelegate”中注册

包含头文件“autogentestbindings.hpp”然后注册回调函数:

sc->addRegisterCallback(register_all_autogentestbindings);
在“hello.js”文件适当地方增加以下代码。本机将“init f”函数放在第一个场景。

var myClass=new ts.SimpleNativeClass();
var myStr=myClass.returnsACString();
var label = cc.LabelTTF.create(myStr, "Helvetica", 20.0);
限制

绑定生成器存在以下两个限制

自变量数字参数无法工作,所以需要手动编写包装器
代表类无法工作,所以需要手动绑定,详见下一部分。
手动 JSB 绑定

本指南将介绍利用Cocos2d-x 2.14模板如何在自己的项目中实现JSB绑定。
首先用Cocos2d-js模板创建项目。其次,我们会介绍如何一步一步从JS调用本地函数。最后你便会学会如何从本地代码调用JS代码了。
现在让我们开始!本机使用的Mac OS X作为开发环境。

步骤1. 用Cocos2dx-js模板创建新项目,同时新建一个即将绑定至JS的C++类。

将项目命名为“JSBinding”然后点击“Next”、“ Create”

新建一个类然后实现这个类,等会再将其绑定至JS。
按“command+N”新建一个C++类并命名为“JSBinding”,路径为“OS X\C and C++\C++ Class”。

将以下代码添加到“JSBinding.h”文件中。

#include "cocos2d.h"
#include "ScriptingCore.h"
// Define a namespace to manage your code and make your code clearly
namespace JSB {
class JSBinding: public cocos2d::CCObject
{
public:
static cocos2d::CCScene* scene();
virtual bool init();
CREATE_FUNC(JSBinding);
void functionTest();
};
}
现在实现JSBinding.cpp中的类。如下所示:

bool JSB::JSBinding::init(){
bool bRef = false;
do{
cocos2d::CCLog("JSB init...");
bRef = true;
} while (0);
return bRef;
}
void JSB::JSBinding::functionTest(){
cocos2d::CCLog("Function test...");
}
步骤2. 将C++代码绑定至Java脚本代码

按“command+N”新建C++类,然后命名“JSB_AUTO”路径“OS X\C and C++\C++ Class”。

往“JSB_AUTO.h”文件中增加一些代码

#include "jsapi.h"
#include "jsfriendapi.h"
#include "ScriptingCore.h"
#include "JSBinding.h"
void register_all(JSContext* cx, JSObject* obj);
然后注意“JSB_AUTO.cpp”的实现。

#include "jsapi.h"
#include "jsfriendapi.h"
#include "ScriptingCore.h"
#include "JSBinding.h"
void register_all(JSContext* cx, JSObject* obj);
然后注意“JSB_AUTO.cpp”的实现。

#include "cocos2d.h"
#include "cocos2d_specifics.hpp"
// Binding specific object by defining JSClass
JSClass* jsb_class;
JSObject* jsb_prototype;
// This function is mapping the function “functionTest” in “JSBinding.cpp”
JSBool js_functionTest(JSContext* cx, uint32_t argc, jsval* vp){
JSBool ok = JS_TRUE;
JSObject* obj = NULL;
JSB::JSBinding* cobj = NULL;
obj = JS_THIS_OBJECT(cx, vp);
js_proxy_t* proxy = jsb_get_js_proxy(obj);
cobj = (JSB::JSBinding* )(proxy ? proxy->ptr : NULL);
JSB_PRECONDITION2(cobj, cx, JS_FALSE, "Invalid Native Object");
if (argc == 0) {
cobj->functionTest();
JS_SET_RVAL(cx, vp, JSVAL_VOID);
return ok;
}
JS_ReportError(cx, "Wrong number of arguments");
return JS_FALSE;
}
JSBool js_constructor(JSContext* cx, uint32_t argc, jsval* vp){
cocos2d::CCLog("JS Constructor...");
if (argc == 0) {
JSB::JSBinding* cobj = new JSB::JSBinding();
cocos2d::CCObject* ccobj = dynamic_cast<cocos2d::CCObject*>(cobj);
if (ccobj) {
ccobj->autorelease();
}
TypeTest<JSB::JSBinding> t;
js_type_class_t* typeClass;
uint32_t typeId = t.s_id();
HASH_FIND_INT(_js_global_type_ht, &typeId, typeClass);
assert(typeClass);
JSObject* obj = JS_NewObject(cx, typeClass->jsclass, typeClass->proto, typeClass->parentProto);
JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(obj));
js_proxy_t* p = jsb_new_proxy(cobj, obj);
JS_AddNamedObjectRoot(cx, &p->obj, "JSB::JSBinding");
return JS_TRUE;
}
JS_ReportError(cx, "Wrong number of arguments: %d, was expecting: %d", argc, 0);
return JS_FALSE;
}
// This function is mapping the function “create” when using JavaScript code
JSBool js_create(JSContext* cx, uint32_t argc, jsval* vp){
cocos2d::CCLog("js is creating...");
if (argc == 0) {
JSB::JSBinding* ret = JSB::JSBinding::create();
jsval jsret;
do{
if (ret) {
js_proxy_t* proxy = js_get_or_create_proxy<JSB::JSBinding>(cx, ret);
jsret = OBJECT_TO_JSVAL(proxy->obj);
}
else{
jsret = JSVAL_NULL;
}
} while(0);
JS_SET_RVAL(cx, vp, jsret);
return JS_FALSE;
}
JS_ReportError(cx, "Wrong number of arguments");
return JS_FALSE;
}
void js_finalize(JSFreeOp* fop, JSObject* obj){
CCLOGINFO("JSBindings: finallizing JS object %p JSB", obj);
}
// Binding JSB type
void js_register(JSContext* cx, JSObject* global){
jsb_class = (JSClass *)calloc(1, sizeof(JSClass));
jsb_class->name = "JSBinding";
jsb_class->addProperty = JS_PropertyStub;
jsb_class->delProperty = JS_PropertyStub;
jsb_class->getProperty = JS_PropertyStub;
jsb_class->setProperty = JS_StrictPropertyStub;
jsb_class->enumerate = JS_EnumerateStub;
jsb_class->resolve = JS_ResolveStub;
jsb_class->convert = JS_ConvertStub;
jsb_class->finalize = js_finalize;
jsb_class->flags = JSCLASS_HAS_RESERVED_SLOTS(2);
static JSPropertySpec properties[] = {
{0, 0, 0, JSOP_NULLWRAPPER, JSOP_NULLWRAPPER}
};
// Binding functionTest function
static JSFunctionSpec funcs[] = {
JS_FN("functionTest", js_functionTest, 1, JSPROP_PERMANENT | JSPROP_ENUMERATE),
JS_FS_END
};
// Binding create() function
static JSFunctionSpec st_funcs[] = {
JS_FN("create", js_create, 0, JSPROP_PERMANENT | JSPROP_ENUMERATE),
JS_FS_END
};
// Binding constructor function and prototype
jsb_prototype = JS_InitClass(
cx, global,
NULL,
jsb_class,
js_constructor, 0,
properties,
funcs,
NULL,
st_funcs);
JSBool found;
JS_SetPropertyAttributes(cx, global, "JSB", JSPROP_ENUMERATE | JSPROP_READONLY, &found);
TypeTest<JSB::JSBinding> t;
js_type_class_t* p;
uint32_t typeId = t.s_id();
HASH_FIND_INT(_js_global_type_ht, &typeId, p);
if (!p) {
p = (js_type_class_t* )malloc(sizeof(_js_global_type_ht));
p->type = typeId;
p->jsclass = jsb_class;
p->proto = jsb_prototype;
p->parentProto = NULL;
HASH_ADD_INT(_js_global_type_ht, type, p);
}
}
// Binding JSB namespace so in JavaScript code JSB namespce can be recognized
void register_all(JSContext* cx, JSObject* obj){
jsval nsval;
JSObject* ns;
JS_GetProperty(cx, obj, "JS", &nsval);
if (nsval == JSVAL_VOID) {
ns = JS_NewObject(cx, NULL, NULL, NULL);
nsval = OBJECT_TO_JSVAL(ns);
JS_SetProperty(cx, obj, "JSB", &nsval);
}
else{
JS_ValueToObject(cx, nsval, &ns);
}
obj = ns;
js_register(cx, obj);
}
现在已经完成了大部分工作,但是我们需要在“SpiderMonkey”进行注册。
打开“AppDelegate.cpp”增加以下代码

ScriptingCore* sc = ScriptingCore::getInstance();
sc->addRegisterCallback(register_all); //add this line
步骤3. 内存管理
在register_all函数前增加两个新函数。

JSBool JSB_cocos2dx_retain(JSContext* cx, uint32_t argc, jsval *vp){
JSObject* thisObj = JS_THIS_OBJECT(cx, vp);
if (thisObj) {
js_proxy_t* proxy = jsb_get_js_proxy(thisObj);
if (proxy) {
((CCObject* )proxy->ptr)->retain();
CCLog("Retain succeed!");
return JS_TRUE;
}
}
JS_ReportError(cx, "Invaild native object");
return JS_FALSE;
}
JSBool JSB_cocos2dx_release(JSContext* cx, uint32_t argc, jsval *vp){
JSObject* thisObj = JS_THIS_OBJECT(cx, vp);
if (thisObj) {
js_proxy_t* proxy = jsb_get_js_proxy(thisObj);
if (proxy) {
((CCObject* )proxy->ptr)->release();
CCLog("Release succeed!");
return JS_TRUE;
}
}
JS_ReportError(cx, "Invaild native object");
return JS_FALSE;
}
在register_all函数中增加以下代码:

JS_DefineFunction(cx, jsb_prototype, "retain", JSB_cocos2dx_retain, 0, JSPROP_READONLY | JSPROP_PERMANENT);
JS_DefineFunction(cx, jsb_prototype, "retain", JSB_cocos2dx_release, 0, JSPROP_READONLY | JSPROP_PERMANENT);
步骤4. 使用C++代码回调Java脚本代码
在C++代码回调Java脚本代码之前增加一些代码至“hello.js”文件。

var testJSB = new JSB.JSBinding();
testJSB.callback = function(i, j){
log("JSB Callback" + i + j);
};
然后打开“JSBinding.cpp”在“functionTest”中增加一些代码。

js_proxy_t* p = jsb_get_native_proxy(this);
jsval retval;
jsval v[] = {
v[0] = UINT_TO_JSVAL(32),
v[1] = UINT_TO_JSVAL(88)
};
ScriptingCore::getInstance()->executeFunctionWithOwner(OBJECT_TO_JSVAL(p->obj),
"callback", 2, v, &retval);
使用“executeFunctionWithOwner()”函数简化函数调用程序
步骤5. 绑定测试
在“hello.js”文件中增加以下代码。

var testJSB = new JSB.JSBinding();
testJSB.retain();
testJSB.functionTest();
testJSB.release();
步骤6. 现在取出(check out)项目
如果你的绑定程序正确无误,将会在调试窗口看到如下界面:

恭喜你成功将JS绑定至本地代码!

只能做成OCX控件供JS调用。

  • 濡備綍灏哻++缁戝畾鑷砵avascript
    绛旓細姝ラ1. 鐢–ocos2dx-js妯℃澘鍒涘缓鏂伴」鐩,鍚屾椂鏂板缓涓涓嵆灏缁戝畾鑷JS鐨凜++绫汇傚皢椤圭洰鍛藉悕涓衡淛SBinding鈥濈劧鍚庣偣鍑烩淣ext鈥濄佲 Create鈥濇柊寤轰竴涓被鐒跺悗瀹炵幇杩欎釜绫,绛変細鍐嶅皢鍏剁粦瀹氳嚦JS銆傛寜鈥渃ommand+N鈥濇柊寤轰竴涓狢++绫诲苟鍛藉悕涓衡淛SBinding鈥,璺緞涓衡淥S X\C and C++\C++ Class鈥濄傚皢浠ヤ笅浠g爜娣诲姞鍒扳淛SBinding.h鈥濇枃...
  • 鐢Java鐨socket缂栫▼瀹炵幇c/s缁撴瀯绋嬪簭
    绛旓細//灏哊IO閫氶亾閫缁戝畾鍒鎷╁櫒,褰撶劧缁戝畾鍚庡垎閰嶇殑涓婚敭涓簊key SelectionKey skey = ssc.register( selector, SelectionKey.OP_ACCEPT ); /// /// 鎺ユ敹瀹㈡埛绔殑杩炴帴Socket,骞跺皢姝ocket涔熸帴杩炴敞鍐屽埌Selector /// /// while(true){ int num = selector.select();//鑾峰彇閫氶亾鍐呮槸鍚︽湁閫夋嫨鍣ㄧ殑鍏冲績浜嬩欢 if(num<1)...
  • cmd涓娇鐢javac瀵规暣涓寘缂栬瘧鎬庝箞鍔?瀵瑰寘閲岄潰鐨勬煇鍑犱釜java鏂囦欢缂栬瘧鎬庝箞鍔...
    绛旓細濡傛灉鏌愪釜绫绘槸涓涓寘鐨勭粍鎴愰儴鍒,鍒 javac 灏鎶璇ョ被鏂囦欢鏀惧叆鍙嶆槧鍖呭悕鐨勫瓙鐩綍涓,蹇呰鏃跺垱寤虹洰褰曘備緥濡,濡傛灉鎸囧畾 -d c:\myclasses 骞朵笖璇ョ被鍚嶅彨 com.mypackage.MyClass,閭d箞绫绘枃浠跺氨鍙綔 c:\myclasses\com\mypackage\MyClass.class銆 鑻ユ湭鎸囧畾 -d 閫夐」,鍒 javac 灏嗘妸绫绘枃浠舵斁鍒颁笌婧愭枃浠剁浉鍚岀殑鐩綍涓傛敞鎰:...
  • c璇█杞寲涓JAVA~~寮勫ソ杩藉姞200鍒!!!
    绛旓細import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;public class Student { String name;int score;public String getName() { return name;} public void setName(String anameme) { this.name = anameme;} public int getScore() { return score;} pub...
  • c璇█涓殑scanf鍦java涓搴旇鎬庝箞琛ㄨ揪?
    绛旓細1銆佷娇鐢 Scanner 绫伙紝Scanner 琚О涓鸿緭鍏ユ祦鎵弿鍣ㄧ被锛屼粠鎺у埗鍙拌鍙栨暟鎹殑 鏋勯犳柟娉 濡備笅锛歋canner绫诲湪 java.util 鍖呬笅锛屼娇鐢ㄦ椂瑕佸姞 import java.util.Scanner;Scanner input = new Scanner(System.in);2銆佷妇渚嬶細Scanner s = new Scanner(System.in);//鍦ㄦ帶鍒跺彴杈撳叆涓涓瓧绗︿覆锛屽洖杞 String str =...
  • 鎷滄墭鎶涓嬮潰C璇█杞java璇█ 涓茬粨鏋勭殑
    绛旓細1銆佸鏋滄槸鍍C璇█涓鏍风敤char鏁扮粍瀵逛覆鏈韩杩涜澶勭悊鐨勮瘽锛屾帹鑽愪互涓嬫柟娉曪細锛1锛Java鐨String绫讳笌char[]涔嬮棿鐨勮浆鎹細String a = "This is a string.";char[] b = a.toCharArray(); // 灏嗕竴涓猄tring绫诲瀷杞垚char鏁扮粍 char[] c = {'a', 'b', 'c'};String d = new String(c); /...
  • JAVA 灏'a' "b" "c" 浠庢帶鍒跺彴瀛樺叆鏁扮粍,鐒跺悗鍐嶈緭鍑哄埌鎺у埗鍙?
    绛旓細Scanner sc = new Scanner(System.in);List<String> lst = new LinkedList<>();while (sc.hasNextLine()) { lst.add(sc.nextLine());} for (String s : lst) { System.out.println(s);}
  • 鍦java涓浣杈撳叆涓涓猚har鍨嬪瓧绗︺
    绛旓細鍦Java涓锛岃嫢闇杈撳叆涓涓瓧绗︼紝鍙互閫氳繃Scanner绫诲疄鐜般備互涓嬫槸璇︾粏鐨勬楠わ細棣栧厛锛屼綘闇瑕佸垱寤轰竴涓猄canner瀵硅薄锛屽皢鐢ㄦ埛鐨勮緭鍏ヨ繛鎺鍒绋嬪簭锛屼緥濡傦細1.閫氳繃浠ヤ笅浠g爜鍒涘缓Scanner瀵硅薄锛歋cannersc=newScanner(System.in);鐒跺悗锛岃皟鐢⊿canner瀵硅薄鐨刵ext()鏂规硶鏉ヨ幏鍙栫敤鎴疯緭鍏ョ殑瀛楃涓诧紝鎺ョ潃灏嗗叾瀛樺偍鍦ㄤ竴涓猄tring绫诲瀷鐨勫彉閲...
  • 鐢∟io鎶鏈疄鐜癱/s缁撴瀯绋嬪簭
    绛旓細//灏哊IO閫氶亾閫缁戝畾鍒鎷╁櫒,褰撶劧缁戝畾鍚庡垎閰嶇殑涓婚敭涓簊key //SelectionKey skey = ssc.register( selector, SelectionKey.OP_ACCEPT ); /// /// 鎺ユ敹瀹㈡埛绔殑杩炴帴Socket,骞跺皢姝ocket涔熸帴杩炴敞鍐屽埌Selector /// /// while(true){ int num = selector.select();//鑾峰彇閫氶亾鍐呮槸鍚︽湁閫夋嫨鍣ㄧ殑鍏冲績...
  • 鑳鎶涓嬮潰鐨刢璇█浠g爜杞崲鎴java浠g爜鍚
    绛旓細import java.util.Scanner;public class Project { public static void main(String[] args) { Scanner sc = new Scanner(System.in);int num, key;key = sc.nextInt();while (key-- != 0) { num = sc.nextInt();int sum = 0;int temp = 5;while (num / temp != 0) { sum =...
  • 扩展阅读:c++和python先学哪个 ... java c++ ... java入门网站 ... c++javapython ... javascript 在线 ... c++和java哪个好就业 ... 为什么都不建议java转测试 ... 先学c++还是先学java ... c++难还是java难 ...

    本站交流只代表网友个人观点,与本站立场无关
    欢迎反馈与建议,请联系电邮
    2024© 车视网