株式会社ライブキャストロゴ 株式会社ライブキャスト

AIR for AndroidでNative Extensionsを試してみた(概要編)
AIR for AndroidでNative Extensionsを試してみた(Androidプロジェクト編)
とAIR for AndroidのNative拡張について書いているのですが、ちょっと間があいてしまいました。すいません…

そうこうしている間に、Adobe Developer ConnectionにもAIR Native Extensionsの記事がアップされました。
ネイティブ拡張(Native Extensions)入門 第2回 ネイティブ拡張の開発方法 前編 | デベロッパーセンター
ネイティブ拡張(Native Extensions)入門 第3回 ネイティブ拡張の開発方法 後編 | デベロッパーセンター

こちらの記事は、使用するクラスやメソッドなどについても詳細に書かれていたり、AndroidだけではなくiOS対応についての記載もありますので、非常に参考になると思います。

さて、前回はAIR for AndroidでNative拡張する際に作成する以下の3つのプロジェクト、

  1. Androidプロジェクトの作成
  2. Flexライブラリプロジェクトの作成
  3. Flexモバイルプロジェクトの作成

のうちの1つ、1.のAndroidプロジェクトを作成し、AndroidのToastクラスを使うライブラリを作成しました。
今回は、このライブラリをActionScriptでラップするようなイメージになる、2.のFlexライブラリプロジェクトを作成したいと思います。

Flexライブラリプロジェクトからswcファイルを作成する

まず、Flash Builderのファイルメニューから「Flexライブラリプロジェクト」を新規作成します。



真ん中あたりの「設定」の部分は、必ず「モバイルライブラリ(モバイルプロジェクトでのみ使用)」を選択してください。

後で実装する際に、flash.external.ExtensionContextが見つからないエラーが出てしまうと思います。





プロジェクトが作成されたら、次に、ActionScriptクラスを新規作成します。



クラスが作成されたら、以下の3つのメソッドを実装します。

package asia.live_cast.ane
{
	import flash.external.ExtensionContext;
	
	public class ToastExtensionLib
	{
		private var context:ExtensionContext;
		
		public function ToastExtensionLib()
		{
			context = ExtensionContext.createExtensionContext("ToastExtension", "type");
		}
		
		public function showLongToast(message:String):void {
			context.call("showLongToast", message);
		}
		
		public function dispose():void {
			context.dispose();
		}
	}
}

コンストラクタでは、拡張IDとコンテキストタイプを指定してExtensionContextオブジェクトをcreateします。

			context = ExtensionContext.createExtensionContext("ToastExtension", "type");

ここで使っているcreateExtensionContextメソッドでは、第一引数には拡張IDを、第二引数にはコンテキストタイプを指定します。

Flexライブラリプロジェクトから呼び出せるようにするために、AIR for AndroidでNative Extensionsを試してみた(Androidプロジェクト編)で作成したFREExtensionインターフェイスを実装したJavaのクラスに対して、任意のIDを命名する必要があります。それが拡張IDになります。

拡張IDとJavaライブラリの関連付けは、拡張記述ファイルというXML形式のファイルで行います。こちらについては後ほど触れたいと思います。

コンテキストタイプには”type”を指定します。

次に、Javaライブラリの関数をcallするメソッドは、AndroidのToastクラスを呼び出す処理の名称を”showLongToast”という名前にしましたので、

result.put(“showLongToast”, new FREFunction() {

AIR for AndroidでNative Extensionsを試してみた(Androidプロジェクト編)より引用。

ExtensionContextオブジェクトのcallメソッドで指定する部分も、”showLongToast”にします。

		public function showLongToast(message:String):void {
			context.call("showLongToast", message);
		}

ここがJavaプロジェクト側と一致していないと、AndroidのNative機能の呼び出しはできません。

disposeメソッドでは、ExtensionContextオブジェクトののdisposeメソッドをコールします。

			context.dispose();

忘れないようにしましょう。

さて、ビルドしてswcファイルを作成しますが、その前に、プロジェクトのプロパティから以下のコンパイルオプションを追加してください。

-swf-version 13



このコンパイルオプションを追加しないと、aneファイルをパッケージングする際に以下のようなエラーが出ますので、要注意です。

Invalid swc file. The extension NameSpace requires the SWF verison to be 13 or lower.

aneファイルのパッケージング

swcファイルも作成できたので、早速、aneファイルをパッケージングしたいところですが、これ以外に必要なファイルがあります。

jarファイルをエクスポートする

AIR for AndroidでNative Extensionsを試してみた(Androidプロジェクト編)で作成したJavaプロジェクトから、jarファイルをエクスポートします。

Flash Builderの「ファイル」メニューから、「エクスポート」を選択し、



「エクスポート先の選択」で「Jarファイル」を選択します。



出力先は、今回作成したFlexプロジェクトのルートフォルダ直下にしました。

library.swfの抽出

まだ他にも必要なものがあります。

library.swfというファイルが必要になります。どこにあるかというと、実はswcの中に包含されています。拡張子をzipファイルに変更して解凍しないといけません。

これを取り出すのは、だいたい以下のような手順になるかと思います。

  • 作成されたswcファイルをコピーする
  • コピーしたファイルの拡張子を.zipにするために、ファイル名をリネームする
  • リネームした.zipファイルを解凍する

そうすると、解凍されたファイルの中にlibrary.swfが存在するのです。ややこしいです…

当方の場合は、以下のようにコマンドをたたいてlibrary.swfを抽出しています。

macbook-2:bin mojamoja$ cp ToastExtension-ane.swc ToastExtension-ane.zip
macbook-2:bin mojamoja$ unzip ToastExtension-ane.zip
Archive: ToastExtension-ane.zip
inflating: library.swf
inflating: catalog.xml
macbook-2:bin mojamoja$ mv library.swf ../

コマンドの最後のところで、library.swfをこのプロジェクトルートのフォルダに移動しています。

拡張記述ファイルの作成

あともう1つ、aneファイルをパッケージングするために必要なファイルがあります。前述の拡張記述ファイルです。

Flash Builderの「ファイル」メニューから、「XMLファイル」を新規作成します。



記述する内容は以下のようになります。

<?xml version="1.0" encoding="UTF-8"?>
<extension xmlns="http://ns.adobe.com/air/extension/2.5">
    <id>ToastExtension</id>
    <versionNumber>1.0.0</versionNumber>
    <platforms>
        <platform name="Android-ARM">
            <applicationDeployment>
                <nativeLibrary>ToastExtension.jar</nativeLibrary>
                <initializer>asia.livecast.ane.ToastExtension</initializer>
                <finalizer>asia.livecast.ane.ToastExtension</finalizer>
            </applicationDeployment>
        </platform>
    </platforms>
</extension>

idは、前述の拡張IDのことを指しています。

context = ExtensionContext.createExtensionContext("ToastExtension", "type");

ExtensionContextオブジェクトのcreate時に指定する拡張IDと、Javaライブラリをここで関連付けするのです。

    <id>ToastExtension</id>

platformはAndroidをターゲットとしているので、以下のような指定になります。

        <platform name="Android-ARM">

nativeLibraryには、先ほどJavaプロジェクトからエクスポートしたjarファイル名を指定します。

                <nativeLibrary>ToastExtension.jar</nativeLibrary>

initializerには、JavaプロジェクトのFREExtensionインターフェイスを実装したクラスを、パッケージ名から指定します。

                <initializer>asia.livecast.ane.ToastExtension</initializer>

finalizerも、initializerと同様に、FREExtensionインターフェイスを実装したクラスを、パッケージ名から指定します。

                <finalizer>asia.livecast.ane.ToastExtension</finalizer>

パッケージ名は「asia.live_cast.ane」になるのですが、あえて「asia.livecast.ane」にしています。自分が所有していない(所有者がいる可能性がある)ドメイン名を使用しているので、あまりよろしくありませんが、このようにしているのは理由があります。

AIR for AndroidでNative Extensionsを試してみた(Androidプロジェクト編)より引用。

実は、asia.live_cast.aneのように、パッケージ名にアンダースコアがあると、aneファイル作成時に以下のようなエラーが出てしまうんです。

extension.xml(9): error 105: extension.platforms.platform.applicationDeployment.initializer contains an invalid value
extension.xml(10): error 105: extension.platforms.platform.applicationDeployment.finalizer contains an invalid value

初めは理由がわからなくて、クラス名だけにしてみたりしたのですが、そうすると今度は実行時にToastExtensionクラスが見つからず落ちてしまったりしてうまくいきません。

TypeError: Error #1009: Cannot access a property or method of a null object reference.

試しにアンダースコアを取り除いてjarファイルを作成してみたところうまくいきました。

という理由で、AIR for AndroidでNative Extensionsを試してみた(Androidプロジェクト編)ではパッケージ名をこのようにしていたのです。

※ ただ、これはバグのような気がします。Javaのプロジェクトでアンダースコアを含むパッケージ名にすることは全く問題ないのですから。

aneファイルを作成する

これで、aneファイルをパッケージングするために必要なすべてのファイルがそろいました。

  • jarファイル
  • swcファイル
  • library.swf
  • 拡張記述ファイル

いよいよaneファイルをパッケージングします。が、Flash Builder 4.6ではできませんので、adtコマンドで行います。

adtコマンドは、<SDKインストールルート>/binにありますので、あらかじめパスを通しておくことをお勧めします。

Flexプロジェクトのルートフォルダに移動して、以下のようなコマンドを実行します。

macbook-2:ToastExtension-ane mojyamojya$ adt -package -storetype pkcs12 -keystore xxxxx.p12 -target ane ToastExtension.ane extension.xml -swc bin/ToastExtension-ane.swc -platform Android-ARM library.swf ToastExtension.jar
password:

かなり、指定するオプションが多いので複雑です。
※ adtコマンドのオプションについては、こちらを参考にどうぞ。
Adobe AIR * ADT package コマンド
※ xxxxx.p12の部分は署名用の証明書になります。適宜、読み替えていただければと思います。

aneファイルが完成しました!

ここまでの操作で構築したフォルダ構成は、このようになりました。



非常にややこしい上に、手作業でやることがかなり多いのでとても長いエントリになってしまいました。このあたりの手作業でやらないといけない部分をFlash Builderが吸収してくれるとありがたいですね。説明するのもなかなか難しいので、わかりにくい部分もあるかと思います。不明点等ありましたらコメントかツイッター等で、ご連絡いただければと思います。

次回は、実際にこのaneファイルを読み込んで、Native拡張を実行するFlexモバイルプロジェクトの作成について、まとめたいと思います。