# cocos-jsb **Repository Path**: pengyouyou/cocos-jsb ## Basic Information - **Project Name**: cocos-jsb - **Description**: 基于ScriptEngine的JS与Native通信中间件,通过JSB绑定实现JS与C++层通信,C++层与Java和OC间分别通过JNI和C++与OC混编实现跨平台函数调用。 - **Primary Language**: C++ - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 4 - **Forks**: 0 - **Created**: 2020-11-08 - **Last Updated**: 2023-12-27 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # cocos-jsb #### 介绍 基于ScriptEngine的JS与Native通信中间件,通过JSB绑定实现JS与C++层通信,C++层与Java和OC间分别通过JNI和C++与OC混编实现跨平台函数调用。 #### 安装教程 1. 将`frameworks`文件夹下文件拷贝到项目`build/jsb-default/frameworks`文件夹下; 2. 在`build/jsb-default/frameworks/cocos2d-x/cocos/Android.mk`中添加编译配置: ```c++ LOCAL_SRC_FILES += \ custom/CustomBridge.cpp \ custom/CustomBridge-android.cpp \ scripting/js-bindings/auto/jsb_cocos2dx_custom_auto.cpp \ ``` > 注意不要加到条件语句里了。 3. 在`build/jsb-default/frameworks/runtime-src/Classes/jsb_module_register.cpp`中添加注册代码: ```c++ #include "cocos/scripting/js-bindings/auto/jsb_cocos2dx_custom_auto.hpp" ... se->addRegisterCallback(register_all_cocos2dx_custom); ... ``` 4. 为在 JS 层无需手动实例化即可使用,将`packages\hot-update`文件夹放到项目目录下,该插件会在每次构建结束后,自动给 `main.js` 附加上为jsb挂载CustomBridge单一实例custom的代码。 5. Android端将`CustomManager.java`文件放到安卓工程`proj.android-studio/app/src/org/cocos2dx/custom/`目录下,在此文件中实现你自己的函数方法。在`AppActivity.java`中相应位置初始化CustomManager以及关联`onActivityResult`方法。 ```java ... CustomManager.init(this); ... CustomManager.onActivityResult(requestCode, resultCode, data); ``` 6. IOS端在`cocos2d_libs.xcodeproj`上右键,将`build/jsb-default/frameworks/cocos2d-x/cocos/custom`文件夹和`jsb_cocos2dx_custom_auto`的`.hpp`和`.cpp`文件添加到工程,在`RootViewController.mm`文件中实现你自己的函数方法。 #### 使用说明 1. JS调用本地函数,`jsb.custom.callNative(method, ?args)`,args支持无参和一个字符串参数: ```javascript var args = { num: 6, obj: { code: 0, msg: "arg message" } }; // 有参调用yourFuncName var res = jsb.custom.callNative("yourFuncName", JSON.stringify(args)); // 无参调用yourFuncName var res = jsb.custom.callNative("yourFuncName"); ``` JS监听本地消息方法: ```javascript // 注册native消息回调 var id = jsb.custom.addListener("any_event_name", (msg) => { cc.log("receive from Native: ", msg); }) ... // 取消监听native消息 jsb.custom.removeListener("any_event_name", id); ``` 2. Android端处理JS端函数`yourFuncName`调用(注意有参和无参时函数定义不同): ```java public static String yourFuncName(final String args) throws JSONException { JSONObject argsObject = new JSONObject(args); Log.d(TAG, "obj:" + argsObject.getJSONObject("obj")); Log.d(TAG, "num:" + argsObject.getInt("num")); return res; } ``` Android端发送`any_event_name`消息: ```java JSONObject jsonObject = new JSONObject(); jsonObject.put("name", "wjw"); jsonObject.put("age", 22); jsonObject.put("school", "商职"); String jsonStr = jsonObject.toString(); callJS("any_event_name", jsonStr); ``` 3. IOS端处理JS端函数`yourFuncName`调用(注意有参和无参时函数定义不同): ```objective-c - (NSString *)yourFuncName: (NSString *) args { ... return res; } ``` IOS端发送`any_event_name`消息: ```c++ #include "custom/CustomBridge.h" jsb::CustomBridge::getInstance()->callJS("any_event_name", res); ``` 4. 一般来说,目前引擎并未承诺多线程下的安全性,所以在开发过程中需要避免 JS 代码在其他线程被调用,以避免各种内存错误。除非明确当前线程是**主线程**,否则需要将 callJS 函数分发到主线程执行。这里我们为确保 callJS 在 JS 引擎所在的线程被执行, 使用`performFunctionInCocosThread`将 callJS 函数逻辑分发到主线程: ```c++ #include "platform/CCApplication.h" ... void CustomBridge::callJS(const std::string &eventName, const std::string &msg) { Application::getInstance()->getScheduler()->performFunctionInCocosThread([=](){ dispatchEvent(eventName, msg); } } ``` ------------ #### 热更新说明 - 版本号约定 App版本号和资源Res版本号均由主版本号、子版本号、修正版本号构成,例如v1.2.3。 - 热更新缓存 目前缓存路径为`jsb.fileUtils.getWritablePath() + 'blackjack-remote-asset'`。App版本更新(即整包更新)时,注意在相应工程修改App版本号(IOS修改`Bundle version string`,Android修改`versionName`),hot-update插件会在App版本号与本地记录的版本号(localStorage字段为`cachedAppVersion`)不匹配时清理本地的热更新缓存。 - 热更新插件 除了上文提到的清理缓存,热更新插件主要做的还有两件事:一是将缓存路径前置到引擎的SearchPaths,二是处理热更新过程中,从临时文件夹拷贝资源到缓存文件夹时意外中断的情况。 - 生成Manifest 我们使用[ version_generator.js 文件 ](https://gitee.com/pengyouyou/cocos-jsb/blob/master/version_generator.js)基于原生打包目录中的 assets 和 src 目录生成本地 Manifest 文件,你可以根据需要修改其中的默认配置: ![](https://gitee.com/pengyouyou/image-bed/raw/master/markdown/20201121124113.png) 使用方式如下: >`node version_generator.js -v 1.2.3 -u https://your-ftp-server/ddzheji/` 其中,`-v` 指定 Manifest 文件的主版本号,`-u` 指定服务器远程包的地址,这个地址需要和最初发布版本中 Manifest 文件的远程包地址一致,否则无法检测到更新。 省略`-u`参数时将使用你配置的packageUrl。 **特别的**,我们为packageUrl的最终路径构成中加入了**Res版本号**: > `manifest.packageUrl += 'v' + manifest.version;` - 热更新发布流程 1. 项目-->构建发布-->构建。注意不要勾选 MD5 Cache,否则会导致热更新无效。 2. 根据构建后的资源目录,执行`version_generator.js`,生成manifest清单文件: >`node version_generator.js -v 1.2.3 -u https://your-ftp-server/ddzheji/` 3. 再次构建,目的是把上一步生成的manifest文件导出到 assets 目录。 4. 将`project.manifest`和`version.manifest`上传到`your-ftp-server/ddzheji/`,将构建生成的`assets`和`src`文件夹上传到`your-ftp-server/ddzheji/v1.2.3`。最终的文件结构可能如下: ![文件结构](https://gitee.com/pengyouyou/image-bed/raw/master/markdown/20201121114740.png) - 原生打包注意事项 原生打包时,往往修改了JS脚本或者Assets文件,因此需要先完成[热更新发布流程](#jump)中的步骤1、2、3。 #### END