今回もAIR for Androidのネイティブ拡張絡みのエントリーです。
「AIR for Android ネイティブ拡張 with Flash CS5.5」でネイティブ拡張のサンプルを3つ程書きましたが、どれも基本的にAIRからネイティブ側を呼び出すだけでした。ExternalInterface.call 的な使い方ですね。
今回はExternalInterface.addCallback 的な使い方について、AlertDialogを例に紹介します。
●ネイティブ側の実装
まずはJavaでネイティブ側を実装します。窓口となる 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.*; public class ANEMain implements FREExtension { public static FREContext context; public FREContext createContext(String arg) { if(context == null) { context = new FREContext(){ @Override public Map<String, FREFunction> getFunctions() { HashMap<String, FREFunction> result = new HashMap<String, FREFunction>(); //ダイアログ result.put("showDialog", new FuncDialog() ); return result; } @Override public void dispose(){ } }; } return context; } public void initialize(){ } public void dispose(){ } }
ANEMainではダイアログを表示するクラスを登録しているだけです。27行目のFuncDialogクラス内でダイアログを作成、表示します。
FuncDialogクラスは以下。
package com.cda244.nativeextension.func; import android.app.Activity; import android.app.AlertDialog; import android.content.DialogInterface; import com.adobe.fre.FREContext; import com.adobe.fre.FREFunction; import com.adobe.fre.FREObject; import com.cda244.nativeextension.ANEMain; public class FuncYNDialog implements FREFunction, DialogInterface.OnClickListener { @Override public FREObject call(FREContext arg0, FREObject[] arg1) { Activity act = arg0.getActivity(); AlertDialog.Builder _alertDialogBuilder; _alertDialogBuilder = new AlertDialog.Builder( act ); _alertDialogBuilder.setCancelable(true); _alertDialogBuilder.setPositiveButton("はい", this); _alertDialogBuilder.setNegativeButton("いいえ", this); _alertDialogBuilder.setTitle("ダイアログのタイトル"); _alertDialogBuilder.setMessage("ダイアログのテキスト"); _alertDialogBuilder.show(); return null; } public void onClick(DialogInterface dialog, int whichButton) { String res=""; if(whichButton == DialogInterface.BUTTON1){ res = "yes"; } else if (whichButton == DialogInterface.BUTTON2){ res = "no"; } ANEMain.context.dispatchStatusEventAsync(res, "fromNative"); } }
call内でダイアログを作成し表示させています。
この際、「はい」「いいえ」ボタンをダイアログに追加し、ボタンクリック時の動作は onClick 内に記述しています。「はい」が押されるとAIRに返す値がyesに、「いいえ」が押されるとnoとなります。
最後に dispatchStatusEventAsync でAIRに結果を渡しています。
以上でネイティブ側の実装は終わりです。jarファイルとして書き出します。
●ane作成
続いてFlash。ANE(というかswc)を作成します。
package com.cda244.nativeextension { import flash.display.*; import flash.events.StatusEvent; 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 callShowDialog():void { context.addEventListener( StatusEvent.STATUS, statusHandler); context.call( "showDialog" ); } private function statusHandler(e:StatusEvent):void { dispatchEvent(e); } } }
ネイティブ側から dispatchStatusEventAsync によってStatusEventがディスパッチされるのでExtensionContextにイベントを貼付けておきます(21行目)。
実際にディスパッチされると、statusHandlerが呼ばれ、statusHandler内でAIRに対してさらにディスパッチされます。
以上で終了です。
library.swcを書き出し、aneにパッケージします。
●AIR作成
ネイティブ拡張に必要なパーツが完成したので最後にAIRを作成します。ネイティブ拡張まわりを管理するANEManagerクラスを作成します。
package ane { import flash.events.StatusEvent; import com.cda244.nativeextension.ANEMain; public class ANEManager { private var _ane:ANEMain; public function ANEManager() { _ane = new ANEMain(); _ane.addEventListener( StatusEvent.STATUS, statusHandler ); } public function showDialog():void { _ane.callShowYNDialog(); } private function statusHandler(e:StatusEvent):void { //ネイティブ拡張から返ってくる値 trace( e.code, e.level); } } }
18行目のshowDialogはネイティブ側にダイアログを表示させる際に使用する関数で、以前のバイブレーションやトースト表示と同種の役割です。
15行目でネイティブ側からディスパッチされた結果を受け取れるようイベントリスナーを貼付けると、ネイティブ側でStatusEventがディスパッチされる際にaneを通してANEManagerのstatusHandlerが呼ばれます。
今回の例だと
e.code →「yes」または「no」
e.level → 「fromNative」
となります。
あとは if や switch でそれぞれの処理を振り分けるだけです。
以上になります。
個人的には Android標準のアクティビティ(ダイアログ)が使用できることで、バックボタンを押す際の処理の一部を考えなくて済むのが助かると思っています。
Androidのバックボタン機能はブラウザの戻るボタンに似ているというか、階層構造ではないにしろProgressionのシーン管理の様な考えが必要になるので、そこの負担を減らせるのはありがたいですね。
助かりました。ありがとう。