Adobe AIR教程:面向iOS設(shè)備的原生擴(kuò)展
本文的主要內(nèi)容如下
AIR Native Extension介紹
ANE的組成部分
ActionScript 3.0擴(kuò)展
Objective-C 擴(kuò)展
使用ADT打包ANE
使用ADT打包IPA
AIR Native Extension介紹
AIR Native Extension (ANE)是AIR 3.0的一項(xiàng)重要特性,簡(jiǎn)單的說(shuō),它允許AIR應(yīng)用程序通過(guò)擴(kuò)展文件與原生應(yīng)用程序類(lèi)庫(kù)相互通訊,從而讓AIR應(yīng)用實(shí)現(xiàn)一些只有原生程序才可以做到的功能。
在ANE出現(xiàn)以前,移動(dòng)平臺(tái)上的AIR對(duì)系統(tǒng)的訪問(wèn)非常有限,功能的實(shí)現(xiàn)都是封裝在封閉的,由Adobe定義好的ActionScript 3.0 API內(nèi),比如Accelerometer, GeoLocator等AS類(lèi)。ANE則將AIR徹底開(kāi)放出來(lái),AIR不再針對(duì)具體的功能提供封閉的API,而是允許開(kāi)發(fā)者通過(guò)AIR的擴(kuò)展機(jī)制自由調(diào)用使用原生語(yǔ)言開(kāi)發(fā)的類(lèi)庫(kù)。這樣可以讓AIR應(yīng)用程序享有與原生應(yīng)用程序同等的機(jī)會(huì),其意義對(duì)Flash技術(shù)來(lái)說(shuō)是劃時(shí)代的。
ANE的組成部分
ANE支持向Windows、Mac OSX、Android和iOS各個(gè)平臺(tái)原生應(yīng)用程序的擴(kuò)展,本文只針對(duì)iOS平臺(tái)進(jìn)行介紹。在iOS平臺(tái)中,ANE的組成部分基本分為ActionScript 3.0擴(kuò)展類(lèi)庫(kù)和Objective-C原生擴(kuò)展類(lèi)庫(kù)兩個(gè)部分,這兩個(gè)部分打包后生成AIR擴(kuò)展文件(.ane),***和AIR應(yīng)用程序一起打包成iOS原生應(yīng)用IPA文件。如下圖所示。

圖1 ANE的組成部分
ActionScript 3.0擴(kuò)展
ANE的AS擴(kuò)展部分是一個(gè)SWC,AIR 3.0 SDK里為flash.external.ExtensionContext類(lèi)添加了新的方法。如下例所示:
- import flash.external.ExtensionContext;
- ...
- private var ext:ExtensionContext;
- ...
- ext = ExtensionContext.createExtensionContext("com.adobe.appPurchase","");
在這個(gè)例子里,ExtensionContext通過(guò)靜態(tài)方法createExtensionContext()來(lái)獲得一個(gè)實(shí)例,參數(shù)com.adobe.appPurchase是這個(gè)擴(kuò)展的ID,它非常重要,在擴(kuò)展的配置文件里和應(yīng)用程序描述文件中都需要用這個(gè)ID進(jìn)行配對(duì)。
調(diào)用原生類(lèi)中定義的方法可以用方法call()來(lái)實(shí)現(xiàn),由于是同步調(diào)用,所以函數(shù)可以有返回值。如在原生類(lèi)中定義的方法finish,可以用下面的代碼來(lái)調(diào)用。
- var result:Object = ext.call("finish");
我們還可以給ExtensionContext類(lèi)添加事件偵聽(tīng),用來(lái)獲取從原生類(lèi)中派發(fā)回來(lái)的事件。
- ext.addEventListener(StatusEvent.STATUS,onStatus);
- public function onStatus(e:StatusEvent):void{
- switch(e.code){
- case "removeTransaction":
- ...
- }
- }
Objective-C 擴(kuò)展
接下來(lái)是原生類(lèi)的部分,如果你注冊(cè)成為蘋(píng)果iOS開(kāi)發(fā)者,那么你可以在蘋(píng)果開(kāi)發(fā)者網(wǎng)站上免費(fèi)下載Object-C的開(kāi)發(fā)工具XCode。關(guān)于如何注冊(cè)成為蘋(píng)果iOS開(kāi)發(fā)者,請(qǐng)參考我的這篇文章,如何成為一個(gè)合法的iOS開(kāi)發(fā)者。
總的來(lái)說(shuō),Objective-C 雖然語(yǔ)法比較奇怪,但只要掌握了基本的規(guī)則,還是和ActionScript一樣易懂。OBJC擴(kuò)展類(lèi)需要引入一個(gè)FlashRuntimeExtension.h類(lèi)包,它實(shí)現(xiàn)了和ActionScript溝通的接口。
引入FlashRuntimeExtension.h之后,可以用下面的代碼定義一個(gè)FREObject方法,F(xiàn)REObject是接口類(lèi)型。這里要注意,與AS的接口包括函數(shù)返回值,都要定義成FREObject類(lèi)型,比如代碼中的retVal。
- FREObject finishTransaction1(FREContext ctx, void* funcData, uint32_t argc, FREObject argv[]) {
- NSLog(@"Finish Transaction Called");
- BOOL matchFound = NO;
- const uint8_t* str = nil;
- uint32_t len = -1;
- ......
- FREObject retVal;
- if(FRENewObjectFromBool(matchFound, &retVal) == FRE_OK){
- return retVal;
- }else{
- return nil;
- }
- }
要把FREObject方法定義成接口,還需要在ContextInitializer方法內(nèi)進(jìn)行配置,如下:
- //這里是需要定義的接口的數(shù)量
- *numFunctionsToTest = 6;
- //定義一個(gè)FRENamedFunction類(lèi)型的實(shí)例func,初始化函數(shù)的個(gè)數(shù)
- FRENamedFunction* func = (FRENamedFunction*)malloc(sizeof(FRENamedFunction)*6);
- //定義一個(gè)接口,name是字符串"getProducts",函數(shù)體是getProducts
- func[0].name = (const uint8_t*)"getProducts";
- func[0].functionData = NULL;
- func[0].function = &getProducts;
- func[1].name = (const uint8_t*)"startPayment";
- func[1].functionData = NULL;
- func[1].function = &startAppPayment;
- func[2].name = (const uint8_t*)"finish";
- func[2].functionData = NULL;
- func[2].function = &finishTransaction1;
- func[3].name = (const uint8_t*)"muted";
- func[3].functionData = NULL;
- func[3].function = &muted;
- func[4].name = (const uint8_t*)"restore";
- func[4].functionData = NULL;
- func[4].function = &restoreTrans;
- func[5].name = (const uint8_t*)"trans";
- func[5].functionData = NULL;
- func[5].function = &getTrans;
- *funcfunctionsToSet = func;
- ....
而ContextInitializer方法,是在原生擴(kuò)展類(lèi)的初始化函數(shù)ExtInitializer中指定的:
- void ExtInitializer(void** extDataToSet, FREContextInitializer* ctxInitializerToSet,
- FREContextFinalizer* ctxFinalizerToSet) {
- NSLog(@"Extension Initialized");
- *extDataToSet = NULL;
- *ctxInitializerToSet = &ContextInitializer;
- *ctxFinalizerToSet = &ContextFinalizer;
- }
ExtInitializer是原生擴(kuò)展的程序入口,它可以通過(guò)擴(kuò)展配置文件extension.xml來(lái)定義:
- com.adobe.appPurchase
- libAppPurchase.a
- ExtInitializer
- ExtFinalizer
我介紹的這個(gè)順序,實(shí)際上就是實(shí)際程序編寫(xiě)的思路,先確定接口,再實(shí)現(xiàn)連接。 也許有朋友和我一開(kāi)始接觸OBJC的時(shí)候一樣,對(duì)這些代碼一頭霧水。沒(méi)有關(guān)系,在這篇教程里我只是對(duì)流程做簡(jiǎn)短的介紹,具體的代碼解析會(huì)在本系列的***一篇教程里做更詳細(xì)的講解。那么接下來(lái)讓我來(lái)介紹下一個(gè)部分,打包擴(kuò)展。
使用ADT打包ANE
在圖1中,我介紹了.ane文件的組成,它包括了AS類(lèi)庫(kù)(.swc)和原生類(lèi)(.a)兩個(gè)部分,以及剛才我們介紹的這個(gè)擴(kuò)展配置文件extension.xml。那么要打包ane我們還需要哪些文件呢?

圖2 打包ANE所需要的文件
如圖2所示,所選擇的文件以及文件夾就是打包ANE所需要的所有文件,它包括:
1,AIR SDK打包應(yīng)用程序和類(lèi)庫(kù)(bin,lib)
2,ActionScript擴(kuò)展類(lèi)包.swc,如圖ANE_IAP_ASLib.swc
3,ActionScript擴(kuò)展類(lèi)包.swf,如圖library.swf,可以通過(guò)將SWC的文件擴(kuò)展名改成ZIP后解壓縮得到。
4,Objective-C擴(kuò)展類(lèi)包.a,如圖libAppPurchase.a,可以通過(guò)在Xcode中編譯項(xiàng)目得到。
5,擴(kuò)展配置文件XML,如圖extension.xml
6,一個(gè)打包證書(shū),如圖selfsigned.p12,可以通過(guò)Flash CS5的AIR發(fā)布設(shè)置生成。
一切就緒后便可以使用命令行進(jìn)行打包,注意路徑,下例路徑為當(dāng)前文件夾。
- bin/adt -package -storetype pkcs12 -keystore selfsigned.p12 -storepass 1234 -target ane ext/InApp.ane extension.xml -swc ANE_IAP_ASLib.swc -platform iPhone-ARM library.swf libAppPurchase.a
使用ADT打包IPA
.ane文件打包成功后,便可以用來(lái)打包IPA文件,也就是iOS應(yīng)用程序包。如果你對(duì)開(kāi)發(fā)iOS應(yīng)用的必要流程還不很清楚,請(qǐng)參閱我的這篇教程,如何使用iOS開(kāi)發(fā)者授權(quán)以及如何申請(qǐng)證書(shū)。我以前介紹過(guò)如何用Flash Professional CS5打包IPA,今天主要介紹如何用AIR SDK的打包工具ADT來(lái)生成含有ANE擴(kuò)展的IPA。

圖3 使用ADT生成含有ANE擴(kuò)展的IPA所需要的文件
如圖3所示,所選擇的文件就是生成IPA的必要文件:
1,應(yīng)用程序文件SWF,如圖是ANE_IAP_Example.swf。
2,開(kāi)發(fā)者設(shè)備授權(quán)文件.mobileprovision,如圖是ghostbride_dev.mobileprovision。
3,開(kāi)發(fā)者簽名證書(shū)文件.p12,如圖是jameslidevelopment.p12。
4,應(yīng)用程序描述文件XML,如圖是info-app.xml。
5,擴(kuò)展包路徑,如圖是ext
6,如果應(yīng)用程序有圖標(biāo)圖片,還需要圖標(biāo)文件夾,如圖是icon
在應(yīng)用描述文件XML中,需要對(duì)擴(kuò)展追加一個(gè)定義:
- com.adobe.appPurchase
這里可以看到,在AS擴(kuò)展類(lèi)、擴(kuò)展配置文件extension.xml和應(yīng)用描述文件info-app.xml中都指定了一個(gè)統(tǒng)一擴(kuò)展的ID: com.adobe.appPurchase。
利用下面的命令行可以打包生成Main.ipa:
- bin/adt -package -target ipa-test-interpreter -provisioning-profile ghostbride_dev.mobileprovision -storetype pkcs12 -keystore jameslidevelopment.p12 -storepass 1234 Main.ipa info-app.xml ANE_IAP_Example.swf -extdir ext icon