在C和Objective-C中绑定JavaScript--------------------------cocos2d-x 3.0正式版本(7.15)
来源:互联网 发布:spark sql seq 编辑:程序博客网 时间:2024/06/03 18:55
引言
C/Objective-C语言中的JavaScript Bindings 是介于本地代码(C or Objective-C)和 JavaScript(JS)代码之间的“胶水”代码(封装代码)。JSB能实现JS和本地代码之间的 互相调用 。
这意味着你可以使用JS在你喜欢的本地库之间互相调用。例如,你可以在JS中创建一个 cocos2d的粒子系统,而它的逻辑和渲染是本地代码执行。或者你可以在JS中创建一个 Chipmunk的物理世界,而所有物理仿真,包括碰撞检测都是本地代码执行。
JSB Layer
JS代码由Mozilla的JS虚拟机(VM)SpiderMonkey解析。使用SpiderMonekey最新的稳 定版本(本文使用的是v14.0.1)。JS VM通过JSB扩展支持自定义类型,自定义结构体和 Objective-C对象。
JSB有一套灵活的重命名规则用来设定哪些类、方法、函数和结构体将被解析或忽略,并确 定哪些方法是回调。为了方便的创建这些规则,它支持正则表达式。
这项技术正被Zynga公司用在游戏的快速开发和原型设计中。现在,让我们在cocos2d-iphone,Chipmunk和CoCosBuilder Reader上使用它。
主要特点
JSB的亮点:
- 支持Objective-C/C的任何库
- 自动生成JS Bindings(“胶水”代码)
- 不需要修改库的源代码,或自动生成的代码
- 有一套强大的规则可定制JS API 的生成
- 自动在JS对象/类型 和 Objective-C对象/结构体/类型 之间相互转换
- 在JS中支持本地对象的子类
- 支持回调
创建自己的Bindings
简明步骤
1.下载JSB(git下载地址)
$git clone git://github.com/zynga/jsbindings.git
2.生成BridgeSupport 文件,假设项目名是CocosDenshion
$cd ~/src/CocosDenshion/CocosDenshion$gen_bridge_metadata -F complete --no-64-bit -c '-DNDEBUG -I.' *.h -o ~/some/path/CocosDenshion.bridgesupport
3.生成补充文件
$cd ~/src/CocosDenshion/CocosDenshion$~/jsb/generate_complement.py -o ~/some/path/CocosDenshion-complement.txt *.h
4.创建JSB配置文件
$vim ~/some/path/CocosDenshion_jsb.ini
5.运行JSB生成脚本
$~/jsb/generate_js_bindings.py -c ~/som/path/CocosDenshion_jsb.ini
6.导入刚才自动生成的文件和JSB源码文件到你的xcode项目中
7.导入SpiderMonkey和JRSwizzle到你的xcode项目
所有文件能在这里找到:
https://github.com/zynga/jsbindings/tree/master/configs/CocosDenshion
详细步骤
JSB中有一个名为generate_js_bindings.py的脚本, 这个脚本会生成“胶水”代码。脚本需 要一个配置文件,其中包含解析规则和BridgeSupport文件。
BridgeSupport文件由OS X下的gen_bridge_metada脚本生成,生成的是一些xml文件包 含了类名,方法名,参数,返回值,内部结构体,常量等信息.
gen_bridge_metada,内部使用clang 解析本地代码。输出的内容是非常可靠的,但不幸的 是,它不完整:丢失了类继承关系、协议和属性信息。这就是为什么JSB包含另一个python脚本generate_js_complement.py, 它生成丢失的信息。
当配置文件准备好,就可以运行generate_js_bindings.py 脚本生成“胶水”代码。
总结,JSB配置文件的结构是
- 解析规则(可选):重命名规则、类的解析/忽略 等…
- BridgeSupport文件(必需):类、方法、函数、结构信息
- 补充文件(Objective – CGON):继承结构、协议和属性信息
“glue” code generation
配置规则
有一套强大的配置规则可以转换本地API到自定义的JS API。让我们看看其中一些规则.
重命名规则:
重命名规则允许我们重命名方法名,类名,函数名或结构名。下面示例代码默认的JS API:
// CCAnimation (from cocos2d-iphone v2.0)+(id) animationWithAnimationFrames:(NSArray*)arrayOfAnimationFrames delayPerUnit:(float)delayPerUnit loops:(NSUInteger)loops;
将是:
// uglycc.CCAnimation.animationWithAnimationFrames_delayPerUnit_loops_( frames, delay, loops );
我们可以利用一套简单的规则把这个JS API命名为如下所示的函数:
// more JS friendlycc.Animation.create( frames, delay, loops );
为了做到这一点,我们要把前缀CC从类名中移除, 因为它已经使用了名为cc的JS名字空间。
obj_class_prefix_to_remove = CC
最后,我们添加一个方法的命名规则:
method_properties = CCAnimation # animationWithAnimationFrames:delayPerUnit:loops: = name:”create”,
合并规则:
但是CCAnimation的其它构造函数会发生什么呢?
// CCAnimation supports 4 different constructors+(id) animationWithSpriteFrames:(NSArray*)arrayOfSpriteFrameNames;+(id) animationWithSpriteFrames:(NSArray*)arrayOfSpriteFrameNames delay:(float)delay;+(id) animationWithAnimationFrames:(NSArray*)arrayOfAnimationFrames delayPerUnit:(float)delayPerUnit loops:(NSUInteger)loops;
我们应该做的是创建一个规则,把四个构造函数合并为一个。JSB会根据参数的个数正确 执行. 这个规则如下所示:
method_properties = CCAnimation # animationWithAnimationFrames:delayPerUnit:loops: = name:”create”; merge: “animation” | “animationWithSpriteFrames:” | “animationWithSpriteFrames:delay:”,
JS的代码将看起来像这样:
// calls [CCAnimation animation]var anim = cc.Animation.create();// calls [CCAnimation animnationWithSpriteFrames:]var anim = cc.Animation.create(array);// calls [CCAnimation animnationWithSpriteFrames:delay:]var anim = cc.Animation.create(array, delay);// calls [CCAnimation animationWithAnimationFrames:delayPerUnit:loops:]var anim = cc.Animation.create(array, delay, loops);
回调规则:
JSB支持回调方法,为了把一个函数注册为回调函数,你需要在配置文件中添加一条回调 规则. 例如:
method_properties = CCNode#onEnter = callback,
你也可以重命名回调函数:
method_properties = CCLayer # ccTouchesBegan:withEvent: = callback; name:”onTouchesBegan”,
示例配置:
进一步学习了解配置文件, 可参考下面的例子。
- cocos2d_jsb.ini
- CocosDenshion_jsb.ini
- chipmunk_jsb.ini
- CocosBuilderReader_jsb.ini
JS Bingdings内幕(“胶水”代码)
JS代码绑定允许本地代码和JS代码互相调用。让我们来看看细节:
JS调用本地函数
下面的代码将调用本地C函数ccpAdd():
var p1 = cc.p(0,0);var p2 = cc.p(1,1);// cc.pAdd is a "wrapped" function, and it will call the cocos2d ccpAdd() C functionvar ret = cc.pAdd(p1, p2);
让我们看看本地ccpAdd的声明
CGPoint ccpAdd(const CGPoint v1, const CGPoint v2);
当执行cc.pAdd时,它会调用“粘合剂”的功能代码JSB_ccpAdd。JSB_ccpAdd做了以下事情:
- 把JS参数转换为本地参数
- 调用本地的ccpAdd()函数
- 把本地的返回值转换成JS的返回值
- 转换参数或返回值时 如果遇到错误,则失败
function call flow
JS调用本地实例/类方法
可以从JS调用实例或类的方法。内部逻辑和调用本机函数相似。让我们来看看:
//创建一个精灵并设置其位置为200,200var sprite = cc.Sprite.create('image.png');sprite.setPosition( cc.p(200,200) );cc.Sprite.create("image.png")
将调用“胶水”函数
JSB_CCSprite_spriteWithFile_rect__static
做了以下事情:
- JS字符串转换成本地字符串
- 通过调用 [CCSprite spriteWithFile:@"image.png"]创建一个本地实例
- 本地实例转换成JS对象
- 新创建的实例添加到字典,使用JS对象作为key
- 返回转换后的JS实例
sprite.setPosition(cc.p(200,200)) 将调用“胶水”函数JSB_CCNode_setPosition_,
做了以下事情:
- 通过JS对象作为key,从字典中获取本机实例。
- JS对象转换成CGPoint
- 调用[instance setPosition:p]
- setPosition没有返回值,它返回一个“void”对象给JS
class instantiation flow
instance method flow
从本地调用JS代码
回调函数
可以生成两种类型的回调:
- 在JS中触发回调而在本地执行(前面提到过)
- 在本地触发回调并执行JS代码。也就是所谓的”回调”
例如,cocos2d-iphone的onEnter,onExit,update回调函数。onEnter在本地触发,JS中 可重写这个方法. 在下面这个例子里,JS函数onEnte会被本地代码调用:
var MyLayer = cc.Layer.extend({ctor:function () {cc.associateWithNative( this, cc.Layer );this.init();},onEnter:function() {cc.log("onEnter called");},});
JSB支持回调,且不需要修改被解析库的源代码。JSB要做的是,把原始回调方法和JSB回调方法交换。
完整的流程:
- JSB注册所有交换方法为回调
- 在交换方法调用时:
*调用本地回调函数
*然后调用JS回调函数(如果有)
callbacks flow
脚本执行:
本地代码调用JS脚本,方法如下:
// JSBCore is responsible registering the native objects in JS, among other thingsif( ! [[JSBCore sharedInstance] runScript:@"my_js_script.js"] ) NSLog(@"Error running script");
谁在使用JSB?
JSB已成功应用于下列开源项目:
- cocos2d-iphone v2.1 (develop-v2 branch): 2d game engine for iOS
- CocosDenshion: The sound engine bundled with cocos2d
- CocosBuilder Reader: A reader for the cocos2d world editor
- Chipmunk Physics: 2d rigid body physics engine
cocos2d-iphone的开发分支有3个demo工程使用了JSB:
- JS Tests: cocos2d JS bindings tests
- JS Watermelon With Me: a simple physics game that uses JS bindings for cocos2d, Chipmunk, CocosDenshion and CocosBuilder Reader.
- JS MoonWarriors: A top-down shooter that uses JS bindings for cocos2d
值得一提的是,得益于一套强大的规则,cocos2d-iphone生成的JS API和
cocos2d-HTML5 API是相同的。
Moon Warriors 可以使用cocos2diphone+JSB 或 cocos2dhtml5运行,无需修改一行代码. 试试web版本:Moon Warriors Web
Bugs/局限性
这篇博章时,JSB有下面的bugs或局限。最新清单请访问JSB Homepage.
- 没有JS调试器。SpiderMonKey 15发布后,会添加远程调试功能。
- 没有JS分析工具
- 本地对象控制JS对象的生命周期
这意味着本机对象被释放了,而JS对象仍然存在。
在某些情况下JS对象可能指向一个已经被释放的本机对象, 从而产生逻辑错误。 - 回调函数不支持返回值. 支持参数有限。
- 脚本无法解析BridgeSupport常量。
- 避免使用OS X 10.6(或更老)系统的gen_bridge_metada。建议使用OS X 10.8(Mountain Lion)的gen_bridge_metada来生成BridgeSupport文件。
- 从头做一个新项目是不容易的。Xcode模板即将来临。在此之际,更简单的方法就是通过复制JS“targets”来绑定cocos2d-iphone v2.1。
- 在C和Objective-C中绑定JavaScript--------------------------cocos2d-x 3.0正式版本(7.15)
- 使用JNI进行混合编程:在C/C++中调用Java代码--------------------cocos2d-x 3.0正式版本(7.5)
- Cocos2d-x使用Javascript开发js绑定C++<代码示例>
- cocos2d-x和objective-c中的retain()和release()
- cocos2d-x中通过Jni实现Java与C++的互相调用-------------------cocos2d-x-3.0正式版本(7.3)
- UIWebView中Objective-C和JavaScript通信
- cocos2d-x 使用libjson解析json--------------cocos2d-x 3.0正式版本(7.6)
- Cocos2d-x 屏幕适配新解----------------------cocos2d-x 3.0正式版本(7.17)
- Cocos2D-x 2.0以上版本跨Android开发环境的搭建---------------------cocos2d-x 3.0正式版本(7.2)
- Cocos2d-x 3.0坐标系详解---------------------cocos2d-x3.0正式版本(7.16)
- 对于cocos2d-x 3.0版本与之前版本的区别分析-------------cocos2d-x3.0正式版本(7.1)
- JavaScript和Objective-C交互
- objective-c多态和绑定
- Objective-C动态绑定和多态
- 如何在原有的Objective-C中使用Swift和在Swift中使用Objective-C
- andriod 自编译,打包生成apk文件--------------------cocos2d-x 3.0正式版本(7.7)
- IOS环境搭建与开发入门-------------------cocos2d-x 3.0正式版本(7.8)
- 从游戏概念开始:迈出游戏开发的第一步-----------------------cocos2d-x 3.0正式版本(7.9)
- c++11 特性 final与override关键字
- ubuntu 安装路径
- java用freemarker导出word的问题
- 谨慎使用java自带线程池
- jQuery Ajax向某个页面传值并取得返回的数组
- 在C和Objective-C中绑定JavaScript--------------------------cocos2d-x 3.0正式版本(7.15)
- Java中字符串比较的注意点
- Citrix 服务器虚拟化之六 Xenserver虚拟机创建与快照
- django settings.py 配置文件
- 寒城攻略:Listo 教你 25 天学会 Swift 语言 - 22 Extensions
- Oracle客户端导出表方案
- Tomcat下访问项目不需要输入项目名称的配置方法 .
- 二叉树中序遍历的迭代版本
- poj 1157 little shop of flowers(动归)