イナヅマTVログ

あねらぼ 大阪さん, ANEを作るために必要なことメモ

| 0件のコメント

2012-07-14 あねらぼ 大阪さんへ行ってきました。
http://atnd.org/events/28173

「あねらぼ」はAIRで使用するANEを学習する場所です。
学習すると言っても先生と生徒のような学校形式ではなく、参加者がやりたいことを黙々と作業しながら壁にぶつかったりしたら詳しい方がヒントを与えてくれたり教えてくれたりしてくれます。

あねらぼ 大阪さんは@tokufxugさん(徳さん)がお世話をしてくれています。
とてもとてもお世話になりました。

公開されているANEを使ったことはありましたが、作りたい、作れるようになりたいと参加しました。
教えていただいたことを忘れないためのメモです。
始めたばっかりなので誤解や間違ってることもあるかもです、その点はご指摘下さい。

ANE?

AIRはActionScript, MXMLで作成します。
しかし残念ながら対象プラットフォーム(OS X, Windows, Android, iOS…etc)全ての機能を使えません。

そこでAdobeが提供した解決策がANEです。
ANEはネイティブ(C, JAVA)とActionScriptをつなぐ仕組みです。
ActionScriptで直接使用できない機能を、ネイティブで記述しActionScriptで使用できるようにします。

ネイティブには様々な魅力的なライブラリが存在します。
ANEを開発できればAIRで使うことができるようになります。

ActionScriptでアクセスできないジャイロやバッテリー情報なども操作できるようになります。

以下、AIR for iOSとANEについてになります。

ANE作成に必要なもの

・ネイティブコード開発環境
Xcode, iOS SDKが必要です。
*XcodeをインストールすればSDKも同時にインストールされます。XcodeはApp Storeから入手(無料)できます。
実機テストのためには開発者アカウントが必要です。(有料)
当たり前ですがネイティブコード(Objective-C, C, C++, C#)の知識も必要です。

・ActionScript開発環境
ActionScriptを記述できるアプリケーション。
Flash CS 6, 5.5, Flash Builder, FlashDevelop, FDT…etc
Flex SDK + AIR SDK

ANEの仕組み

Xcode ⇄ swc ⇄ AIR
・ネイティブコード(Xcode project)
・swc(ActionScript + XML)

ANEを作成するためにXcode projectとActionScriptで作られた.asファイルが必要になります。
ADTコマンドで.asファイルは.swcにネイティブは.aneになる(?)<-であってるかな。 swcにはネイティブコードとActionScriptを中継する役割があります。 ネイティブとActionScriptデータの型は当然違うので変換したりネイティブ関数を実行したりイベントをキャプチャする仕組みをswcで作成します。 swcはActionScriptで記述します。 Xcode projectでネイティブ開発を行います。

ANE作成

Xcode projectとswcは密接な関係になります。
swcに記述した機能はXcode projectにも必要になります。

さて、swcとXcode project同時に書ければ問題は無いのですが物理的に不可能です。
どちらを先に開発したら良いのでしょう?
にわとりと卵のどっちが先な話に似ています。

どちらからでも良いのでしょうが、ネイティブ側の機能は知っておかなければならないように思います。

試行錯誤を重ねながらになると行ったり来たりしながらになりそうです。

以下、iBatteryを参考。(というより写経です)

swc作成

[FDT 5.5]
AIR mobile project新規作成
File > New > New FDT Project
AIR + iOSを選択
Application ID: com.inazumatv.ios.Battery
Application Title: Battery
SDK: Flex 4.6 + AIR 3.3

不要なSDK削除
Properties > FDT Build Path > SDK Library
airglobal.swc, core.swc以外を削除

コンパイル・オプション追加
Properties > FDT Compiler
-swf-version=16

package com.inazumatv.ios {
 
	import flash.events.IEventDispatcher;
	import flash.external.ExtensionContext;
 
	/**
	 * @author taikiken
	 */
	public class Battery extends EventDispatcher {
 
		private var _extensionContext : ExtensionContext;
		/**
		 * @param target
		 */
		public function Battery(target : IEventDispatcher = null) {
			super(target);
 
			_extensionContext = ExtensionContext.createExtensionContext('com.inazumatv.ios.battery', '');
		}
 
		public function getLife() : Number {
			return Number(_extensionContext.call('GetBatteryLife'));
		}
 
		public function getState() : int {
			return int(_extensionContext.call('GetBatteryState'));
		}
 
		public function isSupported() : Boolean {
			return Boolean(_extensionContext.call('IsSupported'));
		}
	}
}

EventDispatcher サブClassにします。
ExtensionContext をimportします。
import flash.external.ExtensionContext;

ExtensionContextが最重要Classです。
ネイティブとの橋渡しはExtensionContextを使用して行われます。
ActionScript API Reference: ExtensionContext

1. ExtensionContextインスタンスを作成
ExtensionContext.createExtensionContext(extensionID, contextType):ExtensionContext;

ExtensionContextインスタンス _extensionContext を作成しました。

extensionID: String
文字列で指定します。
ユニーク(唯一)で無ければなりません。
そのためパッケージのようにDNS逆順で指定することが推奨されています。

contextType: String
これ指定しなくてもいいって徳さんは言ってました。
ドキュメントを見ても””やnullでも構わないって書いてあります。

2. ExtensionContextインスタンスを使いネイティブにアクセスする
今回はネイティブに定義した(する予定の)関数を実行しています。

return Number(_extensionContext.call('GetBatteryLife'));
GetBatteryLife がネイティブ側に実装する(された)関数名です。
ネイティブ側からの戻り値はActionScript側でActionScriptの型にキャストします。
上の例はNumberにキャストしています。

swcの書出し。
src上で右クリック
Run as > FDT SWC Library

Xcode project作成

XcodeでANE作成するためのTemplateを作ってくれた方がいます。
github: xcode-template-ane
ダウンロードあるいはgit pullしたら install_templates.sh を実行します。

インストールした AIR Native Extension for iOS テンプレートを使いプロジェクトファイルを作ります。
このテンプレートにはBuildすると.aneファイルを作成してくれるシェル(.sh)ファイルが付いています。

テンプレート作成時にいくつか設定します。
AIR SDKまでのパスが必要です。
AIR SDKをダウンロードして解凍しておきます。

Extension Name: XBattery
Company identifier prefix: com.inazumatv.ios
Directory containing the AIR sdk: Applications/Adobe Flash Builder 4.6/sdks/AIR 3.3
Native extension’s swc file(optional): <上記で作成したswcまでのパス>

extension.xml
Supporting Files > extension.xml
extension.xml のAIRバージョンをSDKと合わせる。
AIR SDK 3.3を指定したので3.3に変更しました。

<extension xmlns="http://ns.adobe.com/air/extension/3.3">
	<id>com.inazumatv.ios.XBattery</id>
	<versionNumber>1</versionNumber>
	<platforms>
		<platform name="iPhone-ARM">
			<applicationDeployment>
				<nativeLibrary>libXBattery.a</nativeLibrary>
				<initializer>XBatteryExtInitializer</initializer>
				<finalizer>XBatteryExtFinalizer</finalizer>
			</applicationDeployment>
		</platform>
		<platform name="default"> 
			<applicationDeployment/> 
		</platform>
	</platforms>
</extension>

AIR SDKから FlashRuntimeExtensions.h をXcodeプロジェクト・フォルダへコピーします。
/include/FlashRuntimeExtensions.h

.h ファイルを編集

// 先頭にUIKitインポートを追加
#import <UIKit/UIKit.h>
 
// 末尾に関数定義を追加
FREObject GetBatteryLife(FREContext ctx, void* funcData, uint32_t argc, FREObject argv[]);
FREObject GetBatteryInfo(FREContext ctx, void* funcData, uint32_t argc, FREObject argv[]);

.m ファイルを編集
拡張の初期化とファイナライズ
関数名は extension.xml の initializerとfinalizerセクションで指定されています。

void XBatteryExtInitializer(void** extDataToSet, FREContextInitializer* ctxInitializerToSet, FREContextFinalizer* ctxFinalizerToSet) 
{
    NSLog(@"Entering XBatteryExtInitializer()");
 
    *extDataToSet = NULL;
    *ctxInitializerToSet = &ContextInitializer;
    *ctxFinalizerToSet = &ContextFinalizer;
 
    NSLog(@"Exiting XBatteryExtInitializer()");
}
void XBatteryExtFinalizer(void* extData) 
{
    NSLog(@"Entering XBatteryExtFinalizer()");
 
    // Nothing to clean up.
    NSLog(@"Exiting XBatteryExtFinalizer()");
    return;
}

XBatteryyExtFinalizer は中身が空になりました。
Adobe Helpを見ても無くても良さそうな感じです。

拡張コンテキストの初期化

void ContextInitializer(void* extData, const uint8_t* ctxType, FREContext ctx, uint32_t* numFunctionsToTest, const FRENamedFunction** functionsToSet)
{
    NSLog(@"Entering ContextInitializer()");
    *numFunctionsToTest = 3;
 
    FRENamedFunction* func = (FRENamedFunction*) malloc(sizeof(FRENamedFunction) * (*numFunctionsToTest));
    func[0].name = (const uint8_t*) "IsSupported";
    func[0].functionData = NULL;
    func[0].function = &IsSupported;
 
    func[1].name = (const uint8_t*)"GetBatteryLife";
    func[1].functionData = NULL;
    func[1].function = &GetBatteryLife;
 
    func[2].name = (const uint8_t*)"GetBatteryInfo";
    func[2].functionData = NULL;
    func[2].function = &GetBatteryInfo;
 
    *functionsToSet = func;
    NSLog(@"Exiting ContextInitializer()");
}

numFunctionsToTestに定義する関数の数をセットします。
IsSupported はこのテンプレートには標準で付いています。
対応しているか否かで処理分岐できるので、機種依存、OS依存機能を使う時は必須かも。

今回は他に”GetBatteryLife”, “GetBatteryInfo”の2つ関数を追加するので3をセットします。
name: 関数名
functionData: 引数
function: 実行関数

.aneを作る

Buildすると.aneができるかと思ったらどこにも見当たりません。
.aまではできたのでどこかの手順が悪いと思われます。

もう少し勉強が必要です。

ANE参考サイト

ヒム・カンパニー 永井さんの翻訳記事
http://www.himco.jp/articles.php
No:115 Adobe AIRのネイティブ拡張の開発
No:116 ジャイロスコープのネイティブ拡張のサンプル
No:117 Flex + iOSによるネイティブ拡張 HelloWorld
No:118 Flash CS 5.5 + iOSによるネイティブ拡張

Adobe Developer Connection [ADC]
Flash Builder 4.6でネイティブ拡張(Native Extensions)を使ってみよう
ネイティブ拡張の開発方法 前編
ネイティブ拡張の開発方法 後編

Native extensions for Adobe AIR

Adobe Help
ネイティブエクステンションの使用
ActionScript 側のコーディング
C を使用したネイティブ側のコーディング

Classmethod.dev(): AIR for Androidでネイティブ拡張を試しました その1

特産の「もっさみな」:「Flash CS 5.5でネイティブ拡張ライブラリを使ってみる。【AIR for iOS編】」の巻

facebook: Lab of Native Extensions

Adobe blog: Xcode template for authoring ANEs

ANE HandsOn Seminar #1 Hello World! for MacOS

AKABANA: AIR 3 Native Extension 5 ExtensionContext

コメントを残す

必須欄は * がついています