翻译一篇文章,20条开发AIR Native Extension的建议
fmms 13年前
<blockquote> <p>原文作者 <a href="/misc/goto?guid=4958334088660268580" target="_blank">Richard Lord</a></p> <p>英文原文:<a href="/misc/goto?guid=4958334089459726805" target="_blank">20-tips-for-creating-air-native-extensions-for-ios</a></p> <p>译者:<a href="/misc/goto?guid=4958334090246596364">James Li</a></p> </blockquote> <p> 过去的三个月中我为 iOS 平台创建了三个 AIR Native Extension 的扩展(在 <a href="/misc/goto?guid=4958334091036818388" target="_blank">Github</a> 中可以找到代码),这些扩展全部被用在我们的游戏 <a href="http://itunes.apple.com/app/id483135193?ls=1&mt=8" target="_blank">Stick Cricket Super Sixes</a> 中,同时我们也总结了很多经验。虽然我记得并不全面,但下面这几条建议,可以给很多打算开发 ANE 项目的开发者助以一臂之力。</p> <p> ————-</p> <p> 文档</p> <p> ————-</p> <p> <strong>1. 开始</strong></p> <p> 这两篇文档对初学者很有帮助,如果你不知道该如何起步,可以从阅读这两篇文档开始。在网络上也有很多好的文章,只要 Google 一下就行了。</p> <ul> <li><a href="/misc/goto?guid=4958334092621781914" target="_blank">Extending Adobe Air</a></li> <li><a href="/misc/goto?guid=4958334093403270333" target="_blank">AIR Native Extension Example: iBattery for iOS</a></li> </ul> <p> <strong>2. 阅读 Adobe 官方文档</strong></p> <p> 大部分的开发所需的资料在这篇<a href="/misc/goto?guid=4958334094216772412" target="_blank"> Adobe’s documentation</a> 中都可以找得到。</p> <p> ——————-</p> <p> 编写 Actionscript 代码</p> <p> ——————-</p> <p> <strong>3. 认真编写 Actionscript API</strong></p> <p> 确保你的 Actionscript 接口是你的项目中想要的。不要往 Actionscript 里被动地照搬 iOS 接口,要像编写常规 Actioscript 类那样定义你的接口。</p> <p> 记住,后期如果修改原生代码只会影响到 ANE 扩展本身,但如果修改 Actionscript 接口则会影响到所有使用该 ANE 的项目。所以在前期要尽可能完善地定义你的 Actionscript 接口。</p> <p> <strong>4. 尽可能在 Actionscript 一端做错误检查</strong></p> <p> 为了避免错误的发生,你需要在调用 ANE 方法的时候做参数合法性的检查,你可以等到调用原生代码时再做检查,但如果提前在调用 Actionscript 接口的时候就做检查会更简单一些。如果你能保证每次调用原生代码时都不会出错,比如参数个数和参数类型,那么完全可以只在 Actionscript 里做判断。</p> <p> 当然,如果你习惯于在C里写错误检查,当然可以。我个人更喜欢在 Actionscript 里做这件事情。</p> <p> <strong>5. 创建一个原生类的替身</strong></p> <p> 即使你打算仅为 iOS 写扩展,我也建议你创建一个原生类库的替身。用纯 Actionscript 代码创建这个替身,这样它就可以为所有的平台所用。在这个替身里按照 iOS 原生接口定义一套纯 Actionscript 接口方法,即使在调用的时候抛异常或者返回空值也没有关系,至少它是合法的 Actionscript 调用,而且可以在其他平台比如桌面上测试使用。</p> <p> 如果不用这样一个替身,你就每次只能在 iOS 设备上做测试,这样会让开发测试工作极为痛苦。相反,如果使用这个替身,你可以在桌面上快速发布应用来测试那些与设备不相关的功能和模块。</p> <p> —————-</p> <p> 编写原生代码</p> <p> —————-</p> <p> <strong>6. 使用 Objective-C来实现苹果的程序接口</strong></p> <p> 你并不是必须要使用 Objective-C,但是如果想要实现苹果的程序接口,用 Objective-C会很方便。否则你需要用C或者C++。</p> <p> <strong>7. 把为 AIR 编写的接口方法写在.m 文件里</strong></p> <p> AIR 和原生代码之间的接口是用C写的,所以你的原生代码需要引用一个包含C代码的文件来实现这些接口。如果你把接口放在.c 文件中,那么你不能使用任何 Objective-C功能(比如你无法用 objective-c的语法去调用 objective-c接口),但是如果你把接口放在了.m 文件就可以。所以用.m 文件会更方便一些。</p> <p> <strong>8. 包含 AIR 原生接口的.m 文件不需要.h 头文件</strong></p> <p> 但是你需要在 XCode 项目设置中的警告选项里把”missing function prototypes”这一项给关掉。</p> <p> <strong>9. 为 initializer 和 finalizer 方法起一个独一无二的名字</strong></p> <p> 很多 ANE 的例子都使用了”extInitializer”和”extFinalizer”来给扩展的入口和出口函数命名。但如果在项目中使用多个 ANE 扩展,这样会导致命名冲突。所以给入口和出口函数起一个独一无二的名字。</p> <p> <strong>10. 在项目中使用宏</strong></p> <p> 在定义接口的时候,你可能需要重复输入很多遍类似这样的代码来定义函数</p> <blockquote> FREObject someFunction (FREContext context, void* functionData, uint32_t argc, FREObject argv[]) </blockquote> <p> 我建议使用宏定义来代替所有这些重复的定义方式。你可以在<a href="/misc/goto?guid=4958334095001025649" target="_blank">这个源文件</a>中找到宏定义的例子。(感谢 <a href="/misc/goto?guid=4958334095797456714" target="_blank">David Wagner</a> 的提供)</p> <p> <strong>11. 把“Enable linking with shared libraries”设置成 yes</strong></p> <p> 网络上很多关于在 XCode 里如何设置这个选项的讨论,有人说”no”有人说”yes”。基本上,说设置成”yes”的说明你的应用在发布的时候需要链接外部类库,这个选项就是这个意思。但是这也意味着你在发布含有此扩展的 AIR 应用时,你必须要告诉编译器你的 iOS SDK 在哪里,这样你才可以使用那些类库。具体看下面第 18 条。</p> <p> 如果你得到这样一个编译错误</p> <blockquote> ld warning: unexpected srelocation type 9 </blockquote> <p> 则你可能要么忘了开启这个选项,要么没有给编译器指明 SDK 的位置。</p> <p> <strong>12. 小心使用线程</strong></p> <p> 你的原生扩展不能在除主线程之外其他线程创建 Actionscript 对象,而且必须要从 AIR 端调用。这样会导致在 Objective-c中使用块的时候问题重重。然而,你可以通过一种途径来达到这个目的,那就是使用 Actionscript ExtensionContext 事件派发机制。方法如下:</p> <p> 1,在一个线程中,创建一个原生对象并储存数据。</p> <p> 2,派发事件给 ExtensionContext,为下一步传送必要的细节。</p> <p> 3,在事件响应的方法中,调用原生接口来获得这个原生对象。</p> <p> 4,在这个被调用的原生方法里,利用该原生对象创建一个 Actionscript 对象。</p> <p> <strong>13. 创建原生 view 对象</strong></p> <p> AIR 应用是在一个标准的 window 对象里运行的,你可以通过下面的方法获得这个 window 对象:</p> <blockquote> [UIApplication sharedApplication].keyWindow </blockquote> <p> 得到 window 对象后你可以给它添加 subviews 来显示原生的 view 对象。</p> <p> ——————–</p> <p> 编译扩展</p> <p> ——————–</p> <p> <strong>14. 批处理编译和测试</strong></p> <p> 当我开发 Game Center 扩展的时候我创建了一个简单的 AIR 应用来测试 ANE。</p> <p> 我创建了一个 ANT 脚本来编译整个扩展(编译原生C类,编译 AS3 类,编译 AS3 原生替身类,并把它们全部打包入 ANE 里)。</p> <p> 结果就是,在 Eclipse 里点击一次,我就可以编译和测试整个项目,下一步就是拖入设备直接测试应用了(XCode 里的 Organiser 可以很方便的实现这步)。总共花了差不多 10 秒钟的时间来打包,虽然仍然比理想的多了 9 秒,但已经比我见过的大多数工作流都要好很多。</p> <p> 也许用 Flash Builder 有更好的方法(因为我用的是 FDT),而且你当然不必使用 ANT,任何编译工具都可以达到这个效果。但是你需要尽可能的使用流水线的方式来编译和测试这个流程。如果你需要这些代码,可以在 <a href="/misc/goto?guid=4958334096598003138" target="_blank">Game Center extension project</a> 里找到。</p> <p> <strong>15. 使用第三方类库</strong></p> <p> 如果你正在扩展里使用一个第三方类库(比如在 <a href="/misc/goto?guid=4958334097381421341" target="_blank">Flurry extension</a> 里的 Flurry 统计类库),你需要在编译的时候使用“-platform iPhone-ARM” 参数来引用这个类库。</p> <p> <strong>16. 你可能需要使用 platform.xml</strong></p> <p> 如果你会用到任何一个但不是大多数的 iOS SDK 类库,你需要创建一个 <a href="/misc/goto?guid=4958334098182261147" target="_blank">platform.xml</a> 文件来指明你需要使用的类库,以及应用所需要的最小 iOS 版本。我为每一个扩展都创建了一个 platform.xml 文件,因为在使用 AIR3.1 编译时会出现一个有关未知最小 iOS 版本的警告,使用这个文件会隐藏这个警告。</p> <p> —————–</p> <p> 打包应用</p> <p> —————–</p> <p> <strong>17. 如果 IDE 编译的时候并不依赖原生扩展,则你的应用需要引用扩展替身 swc 来保证运行成功 </strong></p> <p> 这个 SWC 里包括了一整套与原生扩展相同的 Actionscript 接口,所以你可以使用它进行编译,并且在开发的时候用来测试。当然,不依赖原生扩展的 IDE 不会正确地发布移动应用,但你可以用我介绍过的那种批处理编译脚本来实现最终的正常编译。</p> <p> <strong>18. 发布 AIR 应用的时候,指明需要引用的 iOS SDK 地址</strong></p> <p> 默认情况下,AIR 编译器会使用 iOS SDK 4.0 来编译应用。如果你使用了这个版本里所不包括的新功能,则编译的时候就会出错。这时需要指明 iOS SDK 的新版本位置,从而实现对新功能类库的引用。在<a href="/misc/goto?guid=4958334098974096305" target="_blank">这篇文章</a>中查看详细信息。在 Flash Builder 里,在配置原生扩展的某个面板中可以进行这个设置,但如果你使用命令行来编译,可以使用-platformsdk 标签来指定 iOS SDK 的路径。</p> <p><strong> 19. ld: warning: ARM function not 4-byte aligned</strong></p> <p> 在编译应用的时候你可能会遇到多处下面这样的警告:</p> <blockquote> ld: warning: ARM function not 4-byte aligned </blockquote> <p> 这些只是警告,不用去理它。4位对齐只是一个优化,并非是必须的。</p> <p> —————–</p> <p> 最后的最后</p> <p> —————–</p> <p> <strong>20. 让你的原生扩展更加通用</strong></p> <p> 当完成了扩展的开发,你可以有三个选择:</p> <p> 1, 只让自己使用。</p> <p> 2, 向其他开发者开源。</p> <p> 3, 卖给其他开发者。</p> <p> 你可以问问自己,是什么让你的应用独一无二。如果原因不是你的原生扩展(实际上很少是因为这个),那么请选择第二个或者第三个,如果每个人都这么做,你也会从中受益。</p> <p> 另外,让更多人从你的扩展中受益,可以让 Adobe AIR 这项技术在移动开发领域里更加强大和稳定。这会鼓励其他的开发者去使用 AIR,也会鼓励 Adobe 继续开发和改进它。</p> <p> 在 <a href="/misc/goto?guid=4958334099769853266" target="_blank">Stick Sports</a> 我们选择了第二项,因为比起花时间来运营我们的原生扩展,我们更愿意花时间来运营和支持我们的游戏。</p>