- creator版本:v2.2.1
- 语言:javascript
学习手动JSB绑定,进行类绑定时运行出错,不知道哪里的问题,麻烦大佬们帮忙看下。
报错信息:
JS: testJSBridge
ERROR: ReferenceError: Can't find variable: ns, location: src/project.dev.js:170:27
STACK:
testJSBridge@src/project.dev.js:170:27
startRequestAuth@src/project.dev.js:165:28
emit@src/cocos2d-jsb.js:16732:22
emitEvents@src/cocos2d-jsb.js:16715:23
_onTouchEnded@src/cocos2d-jsb.js:16301:47
src/cocos2d-jsb.js:33212:35
_doDispatchEvent@src/cocos2d-jsb.js:10186:103
dispatchEvent@src/cocos2d-jsb.js:10887:25
_touchEndHandler@src/cocos2d-jsb.js:10078:25
_onTouchEventCallback@src/cocos2d-jsb.js:23216:59
_dispatchEventToListeners@src/cocos2d-jsb.js:23300:108
_dispatchTouchEvent@src/cocos2d-jsb.js:23249:41
dispatchEvent@src/cocos2d-jsb.js:23496:35
handleTouchesEnd@src/cocos2d-jsb.js:31230:37
touchend@src/cocos2d-jsb.js:31432:43
src/cocos2d-jsb.js:31445:22
dispatchEvent@jsb-adapter/jsb-builtin.js:2860:39
jsb-adapter/jsb-builtin.js:2899:33
截图
PS: 参考官方手动教程代码,但是不知道漏了哪一步。
官方教程链接-JSB 2.0 绑定教程
JS端代码:
testJSBridge: function () {
cc.log('testJSBridge');
var myObj = new ns.JSBridge();
// myObj.foo();
}
OC端绑定文件:
- 头文件
#ifndef JSBridge_h
#define JSBridge_h
#include "cocos/scripting/js-bindings/jswrapper/SeApi.h"
bool js_register_ns_JSBridge(se::Object* global);
#endif /* JSBridge_h */
- cpp文件
//
// JSBridge.cpp
// hello_world-mobile
//
// Created by baichao hwang on 2019/12/19.
//
#include "JSBridge.h"
#include "cocos/scripting/js-bindings/manual/jsb_module_register.hpp"
#include "cocos/scripting/js-bindings/manual/jsb_global.h"
//#include "cocos/scripting/js-bindings/jswrapper/SeApi.h"
#include "cocos/scripting/js-bindings/event/EventDispatcher.h"
#include "cocos/scripting/js-bindings/manual/jsb_classtype.hpp"
#include "cocos2d.h"
USING_NS_CC;
static se::Object* __jsb_ns_JSBridge_proto = nullptr;
static se::Class* __jsb_ns_JSBridge_class = nullptr;
namespace ns {
class JSBridge
{
public:
JSBridge()
: xxx(0)
{}
void foo() {
printf("JSBridge::foo\n");
if (_cb != nullptr) {
_cb(xxx);
}
}
static void static_func() {
printf("JSBridge::static_func\n");
}
void setCallback(const std::function<void(int)>& cb) {
_cb = cb;
if (_cb != nullptr)
{
printf("setCallback(cb)\n");
}
else
{
printf("setCallback(nullptr)\n");
}
}
int xxx;
private:
std::function<void(int)> _cb;
};
}
static bool js_JSBridge_setCallback(se::State& s)
{
const auto& args = s.args();
int argc = (int)args.size();
if (argc >= 1)
{
ns::JSBridge* cobj = (ns::JSBridge*)s.nativeThisObject();
se::Value jsFunc = args[0];
se::Value jsTarget = argc > 1 ? args[1] : se::Value::Undefined;
if (jsFunc.isNullOrUndefined())
{
cobj->setCallback(nullptr);
}
else
{
assert(jsFunc.isObject() && jsFunc.toObject()->isFunction());
// 如果当前 JSBridge 是可以被 new 出来的类,我们 使用 se::Object::attachObject 把 jsFunc 和 jsTarget 关联到当前对象中
s.thisObject()->attachObject(jsFunc.toObject());
s.thisObject()->attachObject(jsTarget.toObject());
// 如果当前 JSBridge 类是一个单例类,或者永远只有一个实例的类,我们不能用 se::Object::attachObject 去关联
// 必须使用 se::Object::root,开发者无需关系 unroot,unroot 的操作会随着 lambda 的销毁触发 jsFunc 的析构,在 se::Object 的析构函数中进行 unroot 操作。
// js_cocos2dx_EventDispatcher_addCustomEventListener 的绑定代码就是使用此方式,因为 EventDispatcher 始终只有一个实例,
// 如果使用 s.thisObject->attachObject(jsFunc.toObject);会导致对应的 func 和 target 永远无法被释放,引发内存泄露。
// jsFunc.toObject()->root();
// jsTarget.toObject()->root();
cobj->setCallback([jsFunc, jsTarget](int counter){
// CPP 回调函数中要传递数据给 JS 或者调用 JS 函数,在回调函数开始需要添加如下两行代码。
se::ScriptEngine::getInstance()->clearException();
se::AutoHandleScope hs;
se::ValueArray args;
args.push_back(se::Value(counter));
se::Object* target = jsTarget.isObject() ? jsTarget.toObject() : nullptr;
jsFunc.toObject()->call(args, target);
});
}
return true;
}
SE_REPORT_ERROR("wrong number of arguments: %d, was expecting %d", argc, 1);
return false;
}
SE_BIND_FUNC(js_JSBridge_setCallback)
static bool js_JSBridge_finalize(se::State& s)
{
ns::JSBridge* cobj = (ns::JSBridge*)s.nativeThisObject();
delete cobj;
return true;
}
SE_BIND_FINALIZE_FUNC(js_JSBridge_finalize)
static bool js_JSBridge_constructor(se::State& s)
{
ns::JSBridge* cobj = new ns::JSBridge();
s.thisObject()->setPrivateData(cobj);
return true;
}
SE_BIND_CTOR(js_JSBridge_constructor, __jsb_ns_JSBridge_class, js_JSBridge_finalize)
static bool js_JSBridge_foo(se::State& s)
{
ns::JSBridge* cobj = (ns::JSBridge*)s.nativeThisObject();
cobj->foo();
return true;
}
SE_BIND_FUNC(js_JSBridge_foo)
static bool js_JSBridge_get_xxx(se::State& s)
{
ns::JSBridge* cobj = (ns::JSBridge*)s.nativeThisObject();
s.rval().setInt32(cobj->xxx);
return true;
}
SE_BIND_PROP_GET(js_JSBridge_get_xxx)
static bool js_JSBridge_set_xxx(se::State& s)
{
const auto& args = s.args();
int argc = (int)args.size();
if (argc > 0)
{
ns::JSBridge* cobj = (ns::JSBridge*)s.nativeThisObject();
cobj->xxx = args[0].toInt32();
return true;
}
SE_REPORT_ERROR("wrong number of arguments: %d, was expecting %d", argc, 1);
return false;
}
SE_BIND_PROP_SET(js_JSBridge_set_xxx)
static bool js_JSBridge_static_func(se::State& s)
{
ns::JSBridge::static_func();
return true;
}
SE_BIND_FUNC(js_JSBridge_static_func)
bool js_register_ns_JSBridge(se::Object* global)
{
// 保证 namespace 对象存在
se::Value nsVal;
if (!global->getProperty("ns", &nsVal))
{
// 不存在则创建一个 JS 对象,相当于 var ns = {};
se::HandleObject jsobj(se::Object::createPlainObject());
nsVal.setObject(jsobj);
// 将 ns 对象挂载到 global 对象中,名称为 ns
global->setProperty("ns", nsVal);
}
se::Object* ns = nsVal.toObject();
// 创建一个 Class 对象,开发者无需考虑 Class 对象的释放,其交由 ScriptEngine 内部自动处理
auto cls = se::Class::create("JSBridge", ns, nullptr, _SE(js_JSBridge_constructor)); // 如果无构造函数,最后一个参数可传入 nullptr,则这个类在 JS 中无法被 new JSBridge()出来
// 为这个 Class 对象定义成员函数、属性、静态函数、析构函数
cls->defineFunction("foo", _SE(js_JSBridge_foo));
cls->defineProperty("xxx", _SE(js_JSBridge_get_xxx), _SE(js_JSBridge_set_xxx));
cls->defineFunction("setCallback", _SE(js_JSBridge_setCallback));
cls->defineFinalizeFunction(_SE(js_JSBridge_finalize));
// 注册类型到 JS VirtualMachine 的操作
cls->install();
// JSBClassType 为 Cocos 引擎绑定层封装的类型注册的辅助函数,此函数不属于 ScriptEngine 这层
JSBClassType::registerClass<ns::JSBridge>(cls);
// 保存注册的结果,便于其他地方使用,比如类继承
__jsb_ns_JSBridge_proto = cls->getProto();
__jsb_ns_JSBridge_class = cls;
// 为每个此 Class 实例化出来的对象附加一个属性
__jsb_ns_JSBridge_proto->setProperty("yyy", se::Value("helloyyy"));
// 注册静态成员变量和静态成员函数
se::Value ctorVal;
if (ns->getProperty("JSBridge", &ctorVal) && ctorVal.isObject())
{
ctorVal.toObject()->setProperty("static_val", se::Value(200));
ctorVal.toObject()->defineFunction("static_func", _SE(js_JSBridge_static_func));
}
// 清空异常
se::ScriptEngine::getInstance()->clearException();
return true;
}


抱歉这方面初学者。

