ANE内部结构探究

原文地址:

http://blog.sina.com.cn/s/blog_5d323f950101d6rc.html

http://blog.sina.com.cn/s/blog_5d323f950101d4a4.html

继上一篇创建一个简单ANE后,今天在这里将我在开发ANE过程中的一些心得和大家分享一下。主要是悟出来的一些关于ANE内部结构的心得。同时也参考了ADOBE的文档针对 Adobe AIR 开发本机扩展。也推荐你去阅读。然后将你的收获不吝和我分享。  ^_^ 

如果你对关于怎么创建一个ANE还不是了解,建议你去读我的上一篇文章 创建一个简单ANE(本篇文章的读者朋友需要有创建ANE,打包等的相应知识基础)。这里我就不花太多笔墨讲述操作过程。
1,ANE其实就是一个拓展
这个有点废话。ANE其实就是本地拓展的缩写。不过。我想要讲的是“拓展”这两个字,事实上,是关于ADOBE对他们运行平台的“拓展”的一个设计风格。关于“拓展”,ADOBE现在有两个实现类,都在 flash .external包下, ExternalInterface类和 ExtensionContext类。 ExternalInterface 类是关于AS3部分和运行平台外的JS层的交互,如果你对这个类不是很熟悉。建议你花一点点时间学习一下,虽然内容和ANE无关,但是关于ADOBE的拓展的设计,架构哲学是一样,看了这个类,你再去看 ExtensionContext 类,相信你肯定会非常有感觉,甚至兴奋
接下来,我们看我们真正需要了解的内容 ExtensionContext 。其实,在这里,你只需要知道一点,想调用AS运行平台外的代码(非AS代码,目前可以在AS里通过ExternalInterface 调外部的JS代码,通过ExtensionContext调用外部 JAVA代码和C代码),你只要调用这里的call方法,平台就会帮你调用外部相应的代码。这两个类里都有这个call方法。其实,我觉得这就是ADOBE的“拓展”的设计哲学。
只是 ExtensionContext中的call不是靜态的,所以,你首先需要创建一个 ExtensionContext实例, ExtensionContext中提供了一个 createExtensionContext 静态方法来创建实例。快结束后,还有一个 dispose 方法来销毁实例。所以,在开发ANE,AS部分的代码流程其实就是对这三个方法的调用。
(1)调用 createExtensionContext创建 ExtensionContext实例,(2)调用call让平台来调用相应的外部方法,(3)调用 ExtensionContext 实例的 dispose 方法来销毁自己,完毕。
2,ANE里AS与外部代码的结构
我们来先看下面这幅图。


 
左边部分就是上面提到的ANE内部AS部分的整个过程,其实是调用 createExtensionContext,call,dispose三个方法的流程。而整个图描述的是根据ANE内部体系结构,AS与底层java部分的互动。
当在AS中调用createExtensionContext时,底层相应的操作就是在FREExtension中调用createContext返回一个FREContext子类的实例,这个 FREContext子类实例和AS中返回的ExtensionContext是一一对应的 。至于 createExtensionContext方法中传递的两个参数extensionID和contextType。可能你的应用中引入了多个ANE包,而每个包都有自己的ID,就是在extension.xml中的那个ID标签里的文本。根本这里的参数 extensionID就可以找到相应ID的ANE包。剩下的那个 contextType,在Adobe官方文档听起来好眩晕,其实就是简单的传到java端的一个字符串,没被做过任何处理。别管他那样吹了,你就觉得是在 createContext方法中得到一个很有用的字符串而已。
得到了 ExtensionContext实例后,就是做真正要做的事情了。调用call,执行我们要的逻辑操作。这里会接收两个参数 functionName args。 在ANE内部,在底层其实就是根据你传的 functionName 帮你找到那个标上了名为 functionName的相应方法。在底层java中,这个相应的方法被封装成了FREFunction接口的一个实现类。这个接口有一个也叫call的方法需要java端开发者来实现,系统内部自然的会帮你找到这个FREFunction的实现类并且调用里面的call,在JAVA里返回FREObject,相对于AS里就是OBject类型。
走到最后一步了,一切操作完毕,就是调用ExtensionContext实例里的dispose方法销毁实例。调用了 ExtensionContext实例里的dispose,ANE内部就相应的调用了 FREContext子类实例里的dispose。不过要注意的是,java端里的三个类型 FREExtesnion , FREContext, FREFunction都有相应的dispose。至少他们是怎么相互调用的,欢迎你创建一个测试ANE,logcat出来和我分享。^_^
关于这些内部结构的内容,可以阅读adobe文档 本机扩展体系结构
3,ANE内部的内存管理
我们在第二点 ANE里AS与外部代码的结构 中,一直有提到java里的FREObject类,对应AS里的Object类。此外,从官方文档 访问 ActionScript 对象使用 ActionScript 基元类型和对象 相应的参考文档 里还可以看到有 FREArray,FREByteArray,FREBitmapData。不过我这里要提到的是,其实,AS部分和java部分,这里,是共享一块内存的。只是在不同的两端,名字不一样而已了,操作方法也有一点点不一样。你可以从我上面提到的两处文档里读到更详细的内容。
4,ANE内部的线程
在文档 本机扩展与 NativeProcess ActionScript 类里,提到了ANE是在AS里的线程运行的。这里我分享一个我自己的经验。因为不同的线程的栈内存是不一样的。所以要注意一点,当你在java端的回调方法(比如UI事件操作监听器里)里,可能你把这些都写在了FREFunction的call方法的内部了,但是运行的时候,传过来的参数已经不可用了。因为是在不同的线程里了。其实就是文档里提到的 FREObject 有效性(嘿嘿,自己读去 ^_^)。如果真要回调(其实我觉得一个好的API设计,都是要在最后调用一个回调方法,只是用户可以传空进来),就调用 FREContext里的 dispatchStatusEventAsync()  方法吧(参考 调度异步事件 ),或者是使用context的全局变量,一看 ExtensionContext.actionScriptDataFREContext. getActionScriptData()你就懂。
5,关于swf版本
这里涉及到版本主要是打包ANE时使用的swf版本和编写应用时最后打包的版本。原则就是ANE的版本不能超过应用的版本。
简单的说就是创建ANE的AS部分的时候,导出的swc版本(编译参数--swf-version)应该和拓展描述符文件extension.xml中的命名空间,就是<extension xmlns="http://ns.adobe.com/air/extension/XX">中的XX要一致。而且这两个不能超过应用的--swf-version编辑参数。
 
最后一个建议就是希望你结合官方文档 针对 Adobe AIR 开发本机扩展 来读。特别是我文章中的那些链接。
 

猜你喜欢

转载自kenkao.iteye.com/blog/1949362