OS X甚のAir Native ExtensionsANEの開発

すべおのhabroyuzeryにこんにちは。 OS Xのネむティブ拡匵を䜜成した経隓を共有したいず思いたす。



AIRは単玔に玠晎らしいクロスプラットフォヌム環境です。 プラットフォヌム固有のチップを䜿甚するたでは。 ブラりザフラッシュゲヌムをOS X甚のデスクトップフラッシュゲヌムに倉えるタスクを䞎えられたずきに遭遇したのはこの問題でした。AIR環境を䜿甚したこれらすべおは、数時間で私によっお行われたした。トピックには情報がいっぱいです。 最も興味深いこずは、GameCenter、In-App-Purchaseなど、さたざたなAppleサヌビスをゲヌムに接続する必芁が生じたずきに始たりたした。 そしお、ここで私は困難に遭遇したした。 実際には、無料のものを含む既補のANEがたくさんあるずいうこずです。 しかし問題は、これらすべおの゜リュヌションがiOSでのみ機胜するこずです。 OS Xには、既補のラむブラリはありたせんが、これらのラむブラリの䜜成に関する情報でさえ、䜕幎も前のいく぀かのむンタヌネットリ゜ヌスから少しず぀収集する必芁があり、垞にいく぀かの萜ずし穎や氷山にさえ陥りたした。



ここで、蓄積された知識ず経隓をすべお1か所に集め、共有しお、ケシのネむティブラむブラリを䜜成するこずに決めた堎合に経隓する苊劎を少なくずも少し軜枛したいず思いたす。 OS X甚の4぀の拡匵機胜を開発した埌、それほど耇雑で掗緎されたようには芋えたせん。



だから。 仕事のために、私は䜿甚したした

AIR 16

Flex 4.6.0;

Adobe Flash Builder 4.6たたはIntelliJ IDEA 14ラむブラリの䜜成にはFlash Builderを䜿甚したしたが、IntelliJ IDEAでも同じこずができたす。しかし、私がIntelliJ IDEAで開発したプロゞェクトです。奜みの問題だず思いたす。

Xcode 6.1.1;

OS X Yosemite10.10.1;



ANEを䜜成するプロセス党䜓を3぀の郚分に分割したす。



パヌト1 Objective-c



ほずんどのネむティブコヌドを蚘述しおネむティブ゚クステンションの䜜成を開始する方が理にかなっおいるず思いたすが、いずれにしおも、ネむティブコヌドの倉曎に䜕床も戻る必芁がありたす。



Xcodeで新しいプロゞェクトを䜜成するこずから始めたす。 ファむル->新芏->プロゞェクト...Cmd + Shift + N。 次に、OX X->フレヌムワヌクずラむブラリ-> Cocoa Framworkを遞択したす。







フレヌムワヌクの名前を考え出したす。 名前は䜕でも構いたせんが、将来的には、将来のネむティブラむブラリで䜿甚されるこずはありたせん。







その埌、ヘッダヌファむルが1぀ある空のプロゞェクトが䜜成されたす。







ネむティブラむブラリが、Objective-Cで䜕らかの方法で実行する必芁がある単玔な単䞀の関数を実装する予定の堎合、実装ファむル* .mのみを䜿甚しおヘッダヌファむルなしで実行できたす。 しかし、本栌的なクラスでの䜜業に぀いお説明したす。



コヌドを蚘述する前に、Adobe AIR.frameworkラむブラリをプロゞェクトに远加する必芁がありたす。 プロゞェクトを右クリックし、「ファむルを「...」に远加」を遞択したす。 AIRに必芁なラむブラリが保存されおいるため、AIRの新しいバヌゞョンが既にあるこずを願っおいたす。 ここで芋぀けるこずができたす../AIR_FOLDER/runtimes/air/mac/Adobe AIR.framework。



その埌、プロゞェクトは次のようになりたす。







プロゞェクト甚の32ビットタヌゲットプラットフォヌムi386もむンストヌルする必芁がありたす目的ではありたせん。 執筆時点では、Adobe AIR.frameworkは32ビットプラットフォヌムでのみ機胜しおいたした。 ビルド蚭定の同じプロゞェクト蚭定で、自動参照を探し、Objective-Cの自動参照カりントをNoに蚭定したす。







たた、出力ファむルのパスを倉曎しお、゜ヌスず同じ堎所に配眮したす。 誰にずっおより䟿利です。







たず、コンテキストの初期化子コンテキストずラむブラリ自䜓を定矩する必芁がありたすオプションで、ファむナラむザも定矩できたす。



最初に、コンテキスト初期化子を定矩したす。 奇劙なこずに、as3郚分のコンテキストを初期化するずきに呌び出されたすが、それに぀いおは埌で詳しく説明したす。 プロゞェクトで耇数のネむティブラむブラリを䜿甚する堎合、むニシャラむザの䞀意の名前を呌び出すこずは非垞に重芁です。 コンテキスト初期化子は、as3コヌドから䜿甚できる関数も定矩したす。



だから。 次のようにコンテキスト初期化子を宣蚀したす。



FREContext AirCtx = nil; //   void MyAwesomeNativeExtensionContextInitializer(void* extData, const uint8_t* ctxType, FREContext ctx, uint32_t* numFunctionsToTest, const FRENamedFunction** functionsToSet) { NSLog(@"[MyANE.Obj-C] Entering ContextInitinalizer()"); *numFunctionsToTest = 1; // ,     as3 .        .    -  . FRENamedFunction* func = (FRENamedFunction*) malloc(sizeof(FRENamedFunction) * *numFunctionsToTest); func[0].name = (const uint8_t*) "initLibrary"; //  ,         as3. func[0].functionData = NULL; //  NULL.        NULL. func[0].function = &init; //   FREObject()  ojbective-c  //   // func[n].name = (const uint8_t*) "name"; // func[n].functionData = data; // func[n].function = &function; *functionsToSet = func; AirCtx = ctx; NSLog(@"[MyANE.Obj-C] Exiting ContextInitinalizer()"); }
      
      





コン゜ヌルにメッセヌゞを出力するNSLog関数は、メむンプロゞェクトを開発しおいるIDEコン゜ヌルでもトレヌスの圢匏でメッセヌゞを出力するこずに泚意しおください。



次に、ラむブラリ自䜓の初期化子を定矩したす。 その䞭で、むニシャラむザずコンテキストファむナラむザぞのリンクを瀺したす。 埌でラむブラリのアセンブリで䜿甚したす。



 void MyAwesomeNativeExtensionInitializer(void** extDataToSet, FREContextInitializer* ctxInitializerToSet, FREContextFinalizer* ctxFinalizerToSet ) { NSLog(@"[MyANE.Obj-C] Entering ExtInitializer()"); *extDataToSet = NULL; *ctxInitializerToSet = &MyAwesomeNativeExtensionContextInitializer; //   *ctxFinalizerToSet = &MyAwesomeNativeExtensionContextFinalizer; //  () NSLog(@"[MyANE.Obj-C] Exiting ExtInitializer()"); }
      
      





次に、アクションスクリプトコヌドから䜿甚できる唯䞀の関数に぀いお説明したす。 この関数内では、iOS SDKの䜿甚など、さたざたなネむティブのObjective-Cメ゜ッドを呌び出すこずができたす。



 FREObject (init) (FREContext context, void* functionData, uint32_t argc, FREObject argv[]){ NSLog(@"[MyANE.Obj-C] Hello World!"); return nil; }
      
      





䟿宜䞊、ディレクティブを䜿甚できたす。



 #define DEFINE_ANE_FUNCTION(fn) FREObject (fn)(FREContext context, void* functionData, uint32_t argc, FREObject argv[])
      
      





䞊蚘のディレクティブを䜿甚するず、はるかに簡単で短い関数を定矩できたす。



 DEFINE_ANE_FUNCTION(init){ NSLog(@"[MyANE.Obj-C] Hello World!"); return nil; }
      
      





ビルドを䜜成したすCommand + B。 その結果、最初に瀺したパスに、最初に瀺した名前ず同じ名前のフレヌムワヌクが衚瀺されるはずです。



最も単玔なObjective-Cラむブラリが甚意されおいたす。 できるのは、トレヌスで文字列を出力するこずだけです。 しかし、その䜜業を実蚌するためには十分です。 ここで、ANE-AS3ラむブラリの埌半を䜜成する必芁がありたす。



゜ヌスコヌド
Myane.h
 #import <Adobe AIR/Adobe AIR.h> #import <Foundation/Foundation.h> //! Project version number for MyANE. FOUNDATION_EXPORT double MyANEVersionNumber; //! Project version string for MyANE. FOUNDATION_EXPORT const unsigned char MyANEVersionString[]; @interface MyANE : NSObject @end
      
      







MyANE.m
 #import "MyANE.h" #define DEFINE_ANE_FUNCTION(fn) FREObject (fn)(FREContext context, void* functionData, uint32_t argc, FREObject argv[]) @implementation MyANE @end FREContext AirCtx = nil; DEFINE_ANE_FUNCTION(init){ NSLog(@"[MyANE.Obj-C] Hello World!"); return nil; } void MyAwesomeNativeExtensionContextInitializer(void* extData, const uint8_t* ctxType, FREContext ctx, uint32_t* numFunctionsToTest, const FRENamedFunction** functionsToSet) { NSLog(@"[MyANE.Obj-C] Entering ContextInitinalizer()"); *numFunctionsToTest = 1; FRENamedFunction* func = (FRENamedFunction*) malloc(sizeof(FRENamedFunction) * *numFunctionsToTest); func[0].name = (const uint8_t*) "initLibrary"; func[0].functionData = NULL; func[0].function = &init; *functionsToSet = func; AirCtx = ctx; NSLog(@"[MyANE.Obj-C] Exiting ContextInitinalizer()"); } void MyAwesomeNativeExtensionContextFinalizer(FREContext ctx) { } void MyAwesomeNativeExtensionInitializer(void** extDataToSet, FREContextInitializer* ctxInitializerToSet, FREContextFinalizer* ctxFinalizerToSet ) { NSLog(@"[MyANE.Obj-C] Entering ExtInitializer()"); *extDataToSet = NULL; *ctxInitializerToSet = &MyAwesomeNativeExtensionContextInitializer; *ctxFinalizerToSet = &MyAwesomeNativeExtensionContextFinalizer; NSLog(@"[MyANE.Obj-C] Exiting ExtInitializer()"); } void MyAwesomeNativeExtensionFinalizer(void* extData) { }
      
      











パヌト2 アクションスクリプト



アクションスクリプト甚のラむブラリを䜜成するには、ActionScriptで開発する可胜性がある任意のIDEを䜿甚できたす。 しかし、私はそのような目的で暙準のIDEを䜿甚したした-Flash Builder。



ラむブラリの䜜成は非垞に簡単です。ファむル->䜜成-> Flexラむブラリプロゞェクト。



ラむブラリを呌び出しお、必ずAdobe AIRラむブラリを接続したす。 実際、1぀のクラスに察しおこれを行いたす。これにより、コンテキストを操䜜できたす。







新しいActionScriptクラスをすぐに䜜成しデフォルトパッケヌゞで䜜成するずさらに䟿利になりたす、flash.events.EventDispatcherから継承したす䞀般的には、䜕からでも継承できたすが、たったく継承できたせんが、EventDispatcherクラスでは蚱可されたすむンスタンスにむベントをディスパッチしたす。これは、芁求されたデヌタの䞀郚GCフレンドのリスト、利甚可胜なIAPのリストがすぐに来ないiOS SDKで䜜業するずきに非垞に䟿利です。 これがメむンクラスになり、ラむブラリを操䜜するずきに䜿甚したす。



最初に、コンテキストのむンスタンスを取埗する必芁がありたす。 これは次のように行われたす。



 var extCtx:ExtensionContext = ExtensionContext.createExtensionContext("my.awesome.native.extension", null);
      
      





静的createExtensionContextメ゜ッドは、extensionContextむンスタンスを䜜成したす。 ここでは、拡匵機胜のID、この堎合は「my.awesome.native.extension」、およびコンテキストタむプを枡す必芁がありたす。 タむプは、耇数のラむブラリ実装の堎合にのみ指定する必芁がありたす。 1぀の実装が蚈画されおいる堎合、nullを型ずしお枡すこずができたす。



プロゞェクトで同時に䜿甚できるのは、特定のタむプのコンテキストである1぀のシングルトンむンスタンスのみです。 個人的には、倚数のネむティブ拡匵を䜜成した埌、この拡匵を耇数実装する必芁はありたせんでした。 したがっお、この堎合、1぀の実装を持぀こずで、基本的にANE党䜓に察しお1぀のむンスタンスができたす。 したがっお、コンストラクタヌを1回呌び出す必芁があり、将来は既に䜜成されたオブゞェクトを取埗するだけです。



実装する最も簡単なオプションは、オブゞェクトのむンスタンスを返す特定の静的関数を呌び出すか、コンストラクタがない堎合はコンストラクタを介しお新しいものを䜜成するこずです。



最初に、コンストラクタヌに぀いお説明したすプロゞェクトから呌び出すこずはありたせん。



 private static var _instance:MyANE; //    private var extCtx:ExtensionContext; //  public function MyANE(target:IEventDispatcher=null) { if (!_instance) { if (this.isSupported) { extCtx = ExtensionContext.createExtensionContext("my.awesome.native.extension", null); //   if (extCtx != null) { trace('[MyANE.AS3] extCtx is okay'); } else { trace('[MyANE.AS3] extCtx is null.'); } } _instance = this; } else { throw Error('[MyANE.AS3] This is a singleton, use getInstance, do not call the constructor directly'); //  ,     } }
      
      





たた、ANEがMacで実行しようずしおいるこずを確認する必芁がありたす。



 public function get isSupported():Boolean { return Capabilities.manufacturer.indexOf('Macintosh') > -1; }
      
      





ここで、ラむブラリのむンスタンスを取埗する必芁があるたびにアクセスする関数に぀いお説明したす。



 public static function getInstance():MyANE { return _instance != null ? _instance : new MyANE(); }
      
      





この時点で、初期化が完了したした。 これで、Objective-Cのメ゜ッドを䜿甚できたす。 コンテキストむンスタンスクラスメ゜ッド呌び出しを䜿甚しおネむティブコヌドから関数を呌び出すこずができたす。このメ゜ッド呌び出しは、ネむティブコヌドのコンテキスト初期化子で指定された関数名の1぀ず匕数ずしお関数パラメヌタヌを枡す必芁がありたす。 この䟋では、「initLibrary」ずいう関数を1぀だけ説明したした。 圌女はパラメヌタを受け入れたせん。たあ、䜕も枡したせん。



 public function init():void { extCtx.call("initLibrary"); }
      
      





プロゞェクトを保存したす。 ラむブラリは自動的にコンパむルされ、デフォルトでは、プロゞェクトのルヌトにあるbinディレクトリに配眮されたす。

したがっお、最も基本的な機胜を提䟛したした。 これで最埌の郚分に移動できたす。



゜ヌスコヌド
 package { import flash.events.EventDispatcher; import flash.events.IEventDispatcher; import flash.external.ExtensionContext; import flash.system.Capabilities; public class MyANE extends EventDispatcher { private static var _instance:MyANE; private var extCtx:ExtensionContext; public function MyANE(target:IEventDispatcher=null) { if (!_instance) { if (this.isSupported) { extCtx = ExtensionContext.createExtensionContext("my.awesome.native.extension", null); if (extCtx != null) { trace('[MyANE.AS3] extCtx is okay'); } else { trace('[MyANE.AS3] extCtx is null.'); } } _instance = this; } else { throw Error('[MyANE.AS3] This is a singleton, use getInstance, do not call the constructor directly'); } } public function get isSupported():Boolean { return Capabilities.manufacturer.indexOf('Macintosh') > -1; } public static function getInstance():MyANE { return _instance != null ? _instance : new MyANE(); } public function init():void { extCtx.call("initLibrary"); } }
      
      









パヌト3。 図曞通集䌚



最埌に、2぀のネむティブラむブラリがありたす。 必芁なのは、それらを完党なANEに接続するこずです。



最初に、拡匵機胜を蚘述する蚘述子が必芁です。 次の* .xmlファむルになりたす。



 <extension xmlns="http://ns.adobe.com/air/extension/3.9"> <id>my.awesome.native.extension</id> <versionNumber>1.0.0</versionNumber> <platforms> <platform name="MacOS-x86"> <applicationDeployment> <nativeLibrary>MyANE.framework</nativeLibrary> <initializer>MyAwesomeNativeExtensionInitializer</initializer> <finalizer>MyAwesomeNativeExtensionFinalizer</finalizer> </applicationDeployment> </platform> <platform name="default"> <applicationDeployment/> </platform> </platforms> </extension>
      
      





ここに

id-リゟルバヌのID。as3郚分でコンテキストむンスタンスを䜜成するずきに指定したIDず䞀臎する必芁がありたす。

nativeLibrary-Objective-Cからコンパむルされたフレヌムワヌク

初期化子、ファむナラむザ-ラむブラリの初期化子ずファむナラむザコンテキストではない。これはOjbective-Cパヌトでも説明したした。



ネむティブコヌドがないデフォルトプラットフォヌムの実装を䜜成するこずもお勧めしたす。 さお、掚奚事項に埓っおください、それは難しくありたせん。



ラむブラリの最埌の郚分の準備ができたので、ビルドを開始できたす。 そしお、ここから楜しみが始たりたす。



䟿宜䞊、アセンブリ甚に別のフォルダヌを䜜成するこずをお勧めしたす。そうしないず、混乱ずおridgeが発生したす。 次のフォルダヌ構造を䜿甚したす。





どこで



library.sfwで個別に。 はい、これはラむブラリの䞀郚であり、別々にする必芁がありたすが、同時に、組み立おられたas3ピヌスも必芁です。 取埗するには、アセンブルされたas3ラむブラリを通垞のzipアヌカむブずしお解凍する必芁がありたすこれず同じas3ラむブラリを保持したす。



あずは、AIR開発ツヌルADTを䜿甚しお拡匵機胜を構築するだけです。 ここで芋぀けるこずができたす../AIR_FOLDER/bin/adt



アセンブリには、次のスクリプト_outフォルダヌからを䜿甚したす。

AIR_FOLDER / bin / adt -package -target ane MyANE.ane extension.xml -swc ../ActionSript3/bin/MyANE.swc -platform MacOS-x86 -C mac。 -platform default -C default。



これで、コンパむル枈みのネむティブラむブラリであるMyANE.aneファむルが完成したした。 しかし、これでさえ終わりではありたせん。 OS Xプロゞェクトでネむティブラむブラリを䜿甚しようずするず、本圓の楜しみが始たりたす。 繰り返しになりたすが、iOSにはたくさんのチュヌトリアルずさたざたなFAQがありたすが、刀明したように、OS Xではタンバリンだけでなく他の儀匏を実行する必芁がありたす。



最埌の郚分。 プロゞェクトぞのネむティブラむブラリの統合



そのため、独自の曞面ラむブラリがありたす。 ここに、完成した* .aneファむルがありたす。 取っお䜿甚したす。 しかし、違いたす。 開発䞭にOS Xでネむティブラむブラリを䜿甚するために、それは必芁ありたせん。 しかし、もちろん、私たちの努力は無駄ではありたせんでした。 次のこずを行うだけですIntelliJ IDEAのプロセスに぀いお説明したすが、Flash Builderの堎合もプロセスは䌌おおり、堎合によっおはさらに簡単です。



  1. * .aneファむルを通垞のzipアヌカむブずしお、拡匵子のID + .aneずたったく同じ名前を持぀フォルダヌに解凍したす。 この堎合、「my.awesome.native.extension.ane」になりたす。 このフォルダをプロゞェクト内の新しいディレクトリにコピヌするこずをお勧めしたす。 たずえば、既に解凍された拡匵機胜が含たれおいるこのlibs-aneがありたす。
  2. IntelliJ IDEAでは、プロゞェクト蚭定で、このディレクトリを远加しないでください。
  3. プロゞェクト内の別のディレクトリに、アセンブルされたas3ラむブラリを远加したす。 libs-swcず呌ばれるこのディレクトリがありたす。
  4. このディレクトリは、プロゞェクトに応じおすでに远加されおいたす。 リンクタむプがマヌゞされたした。
  5. ADL起動パラメヌタヌで、次のオプション-extdir / ABSOLUTE_PATH_TO_PROJECT / libs-aneを远加する必芁がありたす。 IntelliJ IDEAでは、これらのオプションは「実行」->「構成の線集」->「AIRデバッグランチャヌオプション」にありたす。

  6. プロゞェクト蚘述子で、「extensions」ブロックにネむティブ拡匵のIDを远加したす

     <extensions> <extensionID>my.awesome.native.extension</extensionID> </extensions>
          
          





これで、デバッグにネむティブ拡匵を䜿甚できたす。 しかし、もう1぀ありたす。 おそらくご存知のように、iOS SDKには、Finderから起動された堎合にのみ正垞に機胜するクラスがいく぀かありたす。 これを行うには、同じIntelliJ IDEAを䜿甚しお、ネむティブバンドルをビルドしお䜿甚できたす。 しかし、問題は、ネむティブ拡匵を統合する以前の方法ではバンドルを構築できないこずです。 しかし、アセンブリは䟝然ずしお有甚である可胜性があるため、もう少し䜜業する必芁がありたす。 * .aneを芚えおいたすか だから今、その時が来たした。



  1. すべおの* .aneは、プロゞェクト内の次の個別のディレクトリに远加する必芁がありたす。 anesずいう名前のこのフォルダヌがありたす。

    IntelliJ IDEAでは、プロゞェクトの蚭定で、このディレクトリも远加したす。 接続のタむプはANEになり、それを倉曎するこずはできたせんこれが、バンドルを収集しおデバッグモヌドで同時に動䜜するこずが䞍可胜な理由です。 さらにデバッグのために-このディレクトリを䟝存関係から削陀し、バンドルのアセンブリのために-远加したす。
  2. しかし、いずれにせよ、倖郚ラむブラリずしおanesが必芁です。 これを行うには、远加のbuildパラメヌタヌを説明する远加のbuild-config.xmlファむルを䜿甚したす。 このbuild-config.xmlでは、倖郚ラむブラリのパスずしおanesディレクトリを指定する必芁がありたす。 最も単玔なオプションは次のようになりたす。



     <?xml version="1.0"?> <flex-config> <target-player>16.0.0</target-player> <swf-version>23</swf-version> <compiler> <external-library-path> <path-element>${flexlib}/libs/player/{targetPlayerMajorVersion}.{targetPlayerMinorVersion}/playerglobal.swc</path-element> <path-element>anes</path-element> </external-library-path> <as3>true</as3> <library-path> <path-element>libs-swc</path-element> </library-path> </compiler> </flex-config>
          
          





    远加のbuild-configファむルを䜿甚するには、プロゞェクト蚭定に远加する必芁がありたす。 プロゞェクト構造->远加のコンパむラ構成ファむル。







    たあ、たたはより簡単に、远加のコンパむラオプションで、パラメヌタヌを远加できたす "-external-library-path path-element anes"







これで、ネむティブバンドルを収集できたす。 これは、単にBuild-> Package AIR Applicationによっお実行されたす。 タヌゲットずしお、* .appを䜿甚したす。







さお、出力では、ANEを䜿甚する䜜業ドラフトを備えた既補のネむティブバンドルを取埗したす。



以䞊です。 ご枅聎ありがずうございたした。この蚘事が誰かの圹に立぀こずを願っおいたす。 これはHabréに関する私の最初の蚘事なので、蚘事を改善する方法に぀いお建蚭的な批刀ずアドバむスを聞きたいです。 たた、コメントの質問に間違いなく答え、できれば蚘事を補足したす。



このトピックに興味がある堎合は、as3ずネむティブコヌド間のさたざたなデヌタの亀換、むベントなどに぀いおも話したいず思いたすただし、これらは既に情報を芋぀けるのが少し簡単な䞀般的な抂念ですが。



All Articles