AIR for Android ネイティブ拡張 with Flash CS5.5

By | 2011年12月9日

この記事は Android Advent Calendar2011という企画の12月9日分(裏)です。
裏表含めて50件のAndroidの記事が集まる素敵な企画です。

これまでの方々がガチエントリーかガチネタかという記事を書いている中、どちらにも振り切れていないので恐縮ですが、先週からAIR for Androidのネイティブ開発(ANE)にハマっているのでその事について書かせていただきます。
先週、Flash CS5.5でAndroidのネイティブ拡張にゼロから取り組んでみる、という記事を書いたのでその続きという形になります。今回は少し実用的なレベルに踏み込んでみます。

●拡張する機能

今回、割とすぐ使いたい(であろう)3つの機能について拡張したいと思います。
・バイブレーション(基本ですから)
・トースト(軽めの通知やアテンションに)
・暗黙的インテント(ツイッターアプリとの連動などに)
どれも戻り値がないので簡単なものばかりです。むしろ前回のハローワールドの方が面倒だったかもしれません。

●jar作成

javaプロジェクト作成は以前と同じです。
パッケージは com.cda244.nativeextension で FREExtension を拡張したメインのクラスはANEMainとしました。

package com.cda244.nativeextension;

import java.util.HashMap;
import java.util.Map;
import com.adobe.fre.FREContext;
import com.adobe.fre.FREExtension;
import com.adobe.fre.FREFunction;
import com.cda244.nativeextension.func.FuncIntent;
import com.cda244.nativeextension.func.FuncVibrate;
import com.cda244.nativeextension.func.FuncToast;

public class ANEMain implements FREExtension
{

	public FREContext createContext(String arg)
	{

		FREContext context = new FREContext()
		{
			@Override
			public Map getFunctions()
			{
				HashMap result = new HashMap();

				//バイブレーション
				result.put( "vibrate", new FuncVibrate() );

				//トースト
				result.put( "showToast", new FuncToast() );

				//インテント
				result.put("throwIntent", new FuncIntent() );

				return result;
			}

			@Override
			public void dispose(){	}
		};
		return context;
	}

	public void initialize(){	}
	public void dispose(){	}
}

このクラスは窓口として機能するだけにしておいて、各機能の中身は9〜11行目でインポートしているクラスに記述しています。Flashから呼ぶ関数名は「vibrate」「showToast」「throwIntent」になります。
続いて、各関数の記述は以下の通りです。

バイブレーション (FuncVibrate)

package com.cda244.nativeextension.func;

import android.content.Context;
import android.os.Vibrator;
import com.adobe.fre.FREContext;
import com.adobe.fre.FREFunction;
import com.adobe.fre.FREObject;

public class FuncVibrate implements FREFunction
{

	@Override
	public FREObject call(FREContext arg0, FREObject[] arg1)
	{

		try{
			//インスタンス取得
			Vibrator v = (Vibrator) arg0.getActivity().getSystemService(Context.VIBRATOR_SERVICE);

			//時間取得
			int time = arg1[0].getAsInt();

			//振動
			v.vibrate(time);
		}catch(Exception e){	}

		return null;
	}
}

トースト (FuncToast)

package com.cda244.nativeextension.func;

import android.widget.Toast;
import com.adobe.fre.FREContext;
import com.adobe.fre.FREFunction;
import com.adobe.fre.FREObject;

public class FuncToast implements FREFunction
{
	private static Toast toast;

	@Override
	public FREObject call(FREContext arg0, FREObject[] arg1)
	{

		try{
			//表示する文字列取得
			String msg = arg1[0].getAsString();

			if( toast != null){
				//表示しているトーストがあれば消す
				toast.cancel();
				toast = null;
			}

			//インスタンス取得
			toast = Toast.makeText( arg0.getActivity(), msg, Toast.LENGTH_SHORT);

			//表示
			toast.show();
		}catch(Exception e){	}

		return null;
	}
}

暗黙的インテント (FuncIntent)

package com.cda244.nativeextension.func;

import android.content.Intent;
import com.adobe.fre.FREContext;
import com.adobe.fre.FREFunction;
import com.adobe.fre.FREObject;

public class FuncIntent implements FREFunction
{

	@Override
	public FREObject call(FREContext arg0, FREObject[] arg1)
	{
		try{
			//他アプリに渡す文字列取得
			String msg = arg1[0].getAsString();

			//インテント作成、設定
			Intent intent = new Intent(Intent.ACTION_SEND);
			intent.putExtra(Intent.EXTRA_TEXT, msg);
			intent.setType("text/plain");

			//渡す
			arg0.getActivity().startActivity(intent);
		}catch(Exception e){
		}
		return null;
	}
}

3つとも、構造はほぼ同じで、call の中が機能によって違うだけです。

これらをまとめてjarファイルを書き出します。

●extension.xml作成

今回のextension.xmlは以下です。jarファイルはane.jarとしました。

<extension xmlns="http://ns.adobe.com/air/extension/2.5">
    <id>com.cda244.nativeextension.ANEMain</id>
    <versionNumber>1.0.0</versionNumber>
    <platforms>
        <platform name="Android-ARM">
        	<applicationDeployment>
                <nativeLibrary>ane.jar</nativeLibrary>
                <initializer>com.cda244.nativeextension.ANEMain</initializer>
                <finalizer>com.cda244.nativeextension.ANEMain</finalizer>
            </applicationDeployment>
        </platform>
    </platforms>
</extension>

●swc、ane作成

ネイティブ側の窓口ができたところで、次はFlash側の窓口を作ります。前回と同様にlibrary.flaを作成後、ドキュメントファイルを以下の様にします。

package com.cda244.nativeextension
{
	import flash.display.*;
	import flash.external.ExtensionContext;

	public class ANEMain extends MovieClip
	{

		private var context:ExtensionContext;

		public function ANEMain()
		{
			//extension.xmlのidタグに指定したクラス名でNative Extensionのコンテキストを取得
			context = ExtensionContext.createExtensionContext("com.cda244.nativeextension.ANEMain", null);
		}

		public function callShowToast( $mes:String="" ):void
		{
			if( $mes != "" ){	context.call( "showToast", $mes );	}
		}

		public function callThrowIntent( $mes:String="" ):void
		{
			if( $mes != "" ){	context.call( "throwIntent", $mes );	}
		}

		public function callVibrate( $time:uint=100 ):void
		{
			context.call( "vibrate", $time );
		}

	}
}

トーストとインテントは空文字以外の時にネイティブ関数を呼び、バイブレーションには引数が無い場合は0.1秒振動するように設定してあります。
なお、0.01秒など、設定時間が短すぎるとバイブレーションが機能しないのでご注意下さい。

ドキュメントクラスの記述が終了しましたらswfとswcを書き出し、先に作成したjarファイルと合わせてaneファイルを作ります。

●AIR作成

ラストのAIR作成は、「Flash CS5.5でAndroidのネイティブ拡張にゼロから取り組んでみる、3」の時と同じ手順です。まずaneファイルを複製して拡張子をswcに変え、flaファイルのライブラリパスに追加します。
swcの設定後は、メインタイムラインの1フレーム目に以下の様に記述します。

import com.cda244.nativeextension.ANEMain;
import flash.text.*;
import flash.events.*;
import flash.display.*;

var ane:ANEMain = new ANEMain();
var txt:TextField = new TextField();
var tBt:MovieClip = new MovieClip();
var vBt:MovieClip = new MovieClip();
var iBt:MovieClip = new MovieClip();

//トースト
txt.x = txt.y = 10;
txt.width = 300;
txt.border=true;
txt.borderColor=0x000000;
txt.type = TextFieldType.INPUT;
txt.multiline=true;
txt.text = "トースト表示テキスト"
addChild( txt );
tBt.x = 340;
tBt.y = 10;
tBt.graphics.beginFill(0x003300);
tBt.graphics.drawRect(0, 0, 100, 100);
tBt.graphics.endFill();
tBt.addEventListener(MouseEvent.CLICK, tBtClick );
addChild( tBt );

//バイブレーション
vBt.x = 10;
vBt.y = 200;
vBt.graphics.beginFill(0xFF0000);
vBt.graphics.drawRect(0, 0, 400, 100);
vBt.graphics.endFill();
vBt.addEventListener(MouseEvent.CLICK, vBtClick);
addChild( vBt );

//インテント
iBt.x = 10;
iBt.y = 400;
iBt.graphics.beginFill(0x0000FF);
iBt.graphics.drawRect(0, 0, 400, 100);
iBt.graphics.endFill();
iBt.addEventListener(MouseEvent.CLICK, iBtClick);
addChild( iBt );

function tBtClick(e:MouseEvent):void
{
	//改行コードを\nに統一する
	var str:String = txt.text.replace(/\n\r/g, "\n");
	str = txt.text.replace(/\r/g, "\n");
	ane.callShowToast( str );
}

function vBtClick(e:MouseEvent):void
{
	ane.callVibrate( 400 );
	ane.callShowToast( "バイブレーション" );
}

function iBtClick(e:MouseEvent):void
{
	ane.callThrowIntent( "暗黙のインテント テスト" );
	ane.callShowToast( "暗黙のインテント テスト" );
}

続いて、app.xmlも忘れずに修正します。
今回はバイブレーションも使うため、extentionsタグの他に権限も追記が必要です。

<uses-permission android:name="android.permission.VIBRATE"/>

extensionsタグは以下。

<extensions>
	<extensionID>com.cda244.nativeextension.ANEMain</extensionID>
</extensions>

あとはswfをパブリッシュし、adtコマンドでapkをパッケージすれば完成です。

●動作確認

端末にインストールして確認すると以下の様な画面になります。

ネイティブ拡張 サンプルアプリ

ネイティブ拡張 サンプルアプリ


ベタ塗りの矩形をタップすると、
・深緑の正方形 → テキストフィールド内のテキストをトーストで表示
・赤い長方形 → 400ミリ秒バイブレーション
・青い長方形 → インテント投げ
を行います。
バイブレーションとインテント投げについては、確認用にトースト表示も行っています。

●おわりに

以上がAIR for Android ネイティブ拡張のサンプル紹介になります。
今回はAIRからは投げっぱなしで大丈夫な処理ばかりだったのですが、ダイアログや通知、Event.DEACTIVATE時にServiceを起動して常駐して、、、等々いろいろな事ができそうな気がします。
ただ、ネイティブ拡張は、ランタイムを通したAIR側とネイティブ側のやり取り(変換)が軽くない処理とのこと(FLASH MEETUP情報)で、あまり頻繁に活用するのは注意が必要です。

One thought on “AIR for Android ネイティブ拡張 with Flash CS5.5

  1. Pingback: FREContext.dispatchStatusEventAsyncでネイティブからのデータを受け取る | cda244 blog

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です