继上一篇​​创建一个简单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内部结构探究_xml


 


左边部分就是上面提到的ANE内部AS部分的整个过程,其实是调用

​createExtensionContext​​,call,dispose三个方法的流程。而整个图描述的是根据ANE内部体系结构,AS与底层java部分的互动。


FREContext子类实例和AS中返回的ExtensionContext是一一对应的 。至于 createExtensionContext方法中传递的两个参数extensionID和contextType。可能你的应用中引入了多个ANE包,而每个包都有自己的ID,就是在extension.xml中的那个ID标签里的文本。根本这里的参数 extensionID就可以找到相应ID的ANE包。剩下的那个 contextType,在Adobe官方文档听起来好眩晕,其实就是简单的传到java端的一个字符串,没被做过任何处理。别管他那样吹了,你就觉得是在 createContext方法中得到一个很有用的字符串而已。


得到了 ExtensionContext实例后,就是做真正要做的事情了。调用call,执行我们要的逻辑操作。这里会接收两个参数 functionName 和 args。 在ANE内部,在底层其实就是根据你传的 functionName 帮你找到那个标上了名为


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.actionScriptData​​​和 ​​FREContext. 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 开发本机扩展​​ 来读。特别是我文章中的那些链接。