在C和Objective-C中绑定JavaScript--------------------------cocos2d-x 3.0正式版本(7.15)
2014-07-16 09:48
453 查看
引言
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下载地址)
2.生成BridgeSupport 文件,假设项目名是CocosDenshion
3.生成补充文件
4.创建JSB配置文件
5.运行JSB生成脚本
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:
将是:
我们可以利用一套简单的规则把这个JS API命名为如下所示的函数:
为了做到这一点,我们要把前缀CC从类名中移除, 因为它已经使用了名为cc的JS名字空间。
obj_class_prefix_to_remove = CC
最后,我们添加一个方法的命名规则:
method_properties = CCAnimation # animationWithAnimationFrames:delayPerUnit:loops: = name:”create”,
合并规则:
但是CCAnimation的其它构造函数会发生什么呢?
我们应该做的是创建一个规则,把四个构造函数合并为一个。JSB会根据参数的个数正确 执行. 这个规则如下所示:
method_properties = CCAnimation # animationWithAnimationFrames:delayPerUnit:loops: = name:”create”; merge: “animation” | “animationWithSpriteFrames:” | “animationWithSpriteFrames:delay:”,
JS的代码将看起来像这样:
回调规则:
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():
让我们看看本地ccpAdd的声明
当执行cc.pAdd时,它会调用“粘合剂”的功能代码JSB_ccpAdd。JSB_ccpAdd做了以下事情:
把JS参数转换为本地参数
调用本地的ccpAdd()函数
把本地的返回值转换成JS的返回值
转换参数或返回值时 如果遇到错误,则失败
function call flow
JS调用本地实例/类方法
可以从JS调用实例或类的方法。内部逻辑和调用本机函数相似。让我们来看看:
将调用“胶水”函数
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会被本地代码调用:
JSB支持回调,且不需要修改被解析库的源代码。JSB要做的是,把原始回调方法和JSB回调方法交换。
完整的流程:
JSB注册所有交换方法为回调
在交换方法调用时:
*调用本地回调函数
*然后调用JS回调函数(如果有)
callbacks flow
脚本执行:
本地代码调用JS脚本,方法如下:
谁在使用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 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;
将是:
// ugly cc.CCAnimation.animationWithAnimationFrames_delayPerUnit_loops_( frames, delay, loops );
我们可以利用一套简单的规则把这个JS API命名为如下所示的函数:
// more JS friendly cc.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 function var 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,200 var 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 things if( ! [[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。
相关文章推荐
- 使用JNI进行混合编程:在C/C++中调用Java代码--------------------cocos2d-x 3.0正式版本(7.5)
- cocos2d-x触摸分发器原理 ------------------------------cocos2d-x 3.0正式版本(7.10)
- cocos2d-x 使用libjson解析json--------------cocos2d-x 3.0正式版本(7.6)
- IOS环境搭建与开发入门-------------------cocos2d-x 3.0正式版本(7.8)
- Cocos2d-x 3.0坐标系详解---------------------cocos2d-x3.0正式版本(7.16)
- Cocos2D-x 2.0以上版本跨Android开发环境的搭建---------------------cocos2d-x 3.0正式版本(7.2)
- 从游戏概念开始:迈出游戏开发的第一步-----------------------cocos2d-x 3.0正式版本(7.9)
- 多层 UI 触摸事件的轻量级设计-------------------cocos2d-x 3.0正式版本(7.19)
- cocos2d-触摸分发原理-----------------cococs2d-x 3.0正式版本(7.18)
- Cocos2d-x 屏幕适配新解----------------------cocos2d-x 3.0正式版本(7.17)
- cocos2dx之音效引擎 ------------------------cocos2d-x 3.0正式版本(7.14)
- andriod 自编译,打包生成apk文件--------------------cocos2d-x 3.0正式版本(7.7)
- cocos2d-x中通过Jni实现Java与C++的互相调用-------------------cocos2d-x-3.0正式版本(7.3)
- 对于cocos2d-x 3.0版本与之前版本的区别分析-------------cocos2d-x3.0正式版本(7.1)
- Cocos2dx 3.0 正式版本开发环境搭建
- 搭建win32 cocos3.0 正式版本 创建项目 最新 2014.4.28
- 一步一步了解Cocos2dx 3.0 正式版本开发环境搭建(Win32/Android)
- Cocos2dx 3.0正式版本UI解析错乱解决方案
- cocos2d-html5 javascript 通过C++绑定,调用java方法
- cocos2d-x-2.2.0版本的CocoStudio的GUI绑定到lua