吉岡です。
URIスキーマを試してみました。
URIスキーマというのは、自分で作成したアプリに対して、固有のURIを指定できる仕組みです。
固有のURIを指定することによって、ブラウザ等からそのURIを使ってアプリを起動する事が
できるようになります。
この固有のURIは、Androidアプリの設定ファイル「AndroidManifest.xml」内で指定します。
…のですが、AIR for AndroidではAndroidManifest.xmlは自動作成されますので、例によって
AIRアプリの設定ファイル内にて、<android>タグを使って書き込みの依頼をしておきます。
具体的には、「appName-app.xml」内に、次のような要素を追加しておきます。
<android>
<manifestAdditions>
<launcherActivity>
<data>
<![CDATA[
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.BROWSABLE"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:scheme="ここにURIスキーマ"/>
</intent-filter>
]]>
</data>
</launcherActivity>
</manifestAdditions>
</android>
<data android:scheme="ここにURIスキーマ"/>の箇所に、自分のアプリを呼び出す際に
使用したい名前を指定するわけですね。
とりあえず「testApp」という名前で登録をしたい場合には、
<data android:scheme="testApp"/>
でOKです。
(このURIスキーマの命名規則はちょっと調べていないのですが、反転ドメイン形式のような
おきまりのルールみたいなのはあるんでしょうか?jpCirueloTestAppのが無難、みたいな。)
この設定を行ったアプリは、ブラウザ上のハイパーリンクテキストから、
URIスキーマを利用して起動できます。
つまりは、
<a href="testApp://">「testApp」として登録したアプリを起動</a>
と、aタグを記述しておき、これをブラウザ上で表示してクリックすればアプリが起動します。
■パラメータを渡す
アプリを起動する際に、何らかの情報をパラメータとして渡したい場合には、
HTTPでのGETのように、URIエンコードしたパラメータを付加する事もできます。
具体的には、
<a href="testApp://arg1=value">「testApp」として登録したアプリを起動</a>
のように記載するわけですね。
■AIRアプリ側で起動されたことを検知するには
さて、この仕組みを使ってブラウザからAIRアプリを起動した場合、アプリ側では
NativeApplicationのinvokeイベントが発生し、invokeイベントのイベントオブジェクトの
argumentsプロパティに、その内容が渡されます。
こんな感じで受ける準備をしておくわけですね。
//NativeApplicationのinvokeイベントで起動時の情報を受ける
var na:NativeApplication = NativeApplication.nativeApplication;
na.addEventListener(InvokeEvent.INVOKE,func)
function func(e:InvokeEvent):void{
msg.text = "起動イベントを受け取りました\r"
//argumentsの長さで起動オプションがあるかどうか(URIスキーマで呼び出されたかどうか)を判定
if(e.arguments.length>0){
msg.appendText("受け取ったパラメータは、" + e.arguments[0].toString())
}else{
msg.appendText("通常起動しました。")
}
}
この時、invokeイベントのイベントオブジェクト内のarguments[0]には、起動時に渡された
文字列が格納されています。単に、
<a href="testApp://">「testApp」として登録したアプリを起動</a>
として起動した場合にも、「testApp://」という文字列が格納されています。
<a href="testApp://arg1=value">「testApp」として登録したアプリを起動</a>
のようなパラメータがある場合は、まるごと「testApp://arg1=value」という文字列が格納されています。
パラメータのパースは自分でやってください、って事なんでしょね。
ともあれ、NativeApplicationのinvokeイベントを使用すれば、URIスキーマによって起動されたかどうかや、
起動時に渡されたパラメータを受け取ることも可能です。
■AIRアプリから直接URIスキーマを利用して他のAIRアプリを起動するには -失敗例
さて、URIスキーマの仕組みを使って、AIRアプリからAIRアプリを起動する事はできるのでしょうか。
ちょっと試した限りは「条件付きでできるけど、ちょっとスマートじゃないぜ」という感じでした。
まずは単純に、navigateToURLで行ってみました。
var req:URLRequest = new URLRequest("testApp://");
flash.net.navigateToURL(req);
これは、セキュリティエラーが送信側のAIRアプリ内で発生し、メッセージを送ることもできずに
コケてしまいました。残念。
■AIRアプリから直接URIスキーマを利用して他のAIRアプリを起動するには -迂回例
どうも普通にリクエストを送ると、セキュリティエラーではじかれてしまうようです。
そこで、StageWebViewを使って、アプリ上にブラウザコンテナを表示し、StageWebView内の
aタグからURIスキーマを設定したアプリを呼び出してみました。
StageWebViewクラスは、AIRアプリ内にブラウザのコンテナを表示する事ができるクラスです。
また、loadStringメソッドを利用すると、任意のHTML表現を持った文字列を、webコンテンツと
して表示してくれます。この仕組みを利用するわけですね。
//簡易ブラウザを表示
var wv:StageWebView = new StageWebView();
var rect:Rectangle = new Rectangle(0,0,480,300);
wv.viewPort = rect;
wv.stage = stage;
//HTMLテキストを流し込み
var xml:XML =
<html>
<body>
<a href = "testApp://"}>URIスキーマを利用して起動</a>
</body>
</html>
wv.loadString(xml.toXMLString());
※設定ファイルに、
<uses-permission android:name="android.permission.INTERNET"/>
の設定が必要です
StageWebViewは、ASではかなり特殊なクラスです。画面に表示する系のクラスなのですが、
表示リストには連なれません。つまりはaddChildやremoveChildで扱えないわけですね。
StageWebViewを表示するには、stageプロパティに、Stageへの参照をセットします。
すると、アプリの最上位に表示されるようになります。
また、とりあえずは「表示専門」といったような用途であり、ASとの細かな連携はできません。
(URIスキーマを使って自分自身にパラメータを渡すことはできますが、冗長ですよね)
しかし、前述したようにloadStringメソッドを使用すれば、表示する内容をゼロから
コントロールする事はできますので、とりあえずURIスキーマ発射台としては使用できます。
あまりスマートとは言えませんが、とりあえずはAIRアプリから他のAIRアプリの起動ができるようになりますね。
■バイナリデータの受け渡しはできるのか
文字列データの受け渡しができる事はわかりましたが、バイナリデータはどうでしょうか?
ちょいと試してみました。URIを使用するので直接バイナリで、というわけにはいかないので、
mxパッケージに用意されているmx.utils.Base64Encoderを利用して、base64エンコードをしてから
渡す作戦で試してみました。
例によって適当なBitmapdataを作成し、それをエンコードして渡しています。
//base64エンコードしたパラメータ付きのURIを作成するヘルパ関数
function createURI():String{
//Bitmapdata → ByteArray(PNGデータ) → String(base64エンコード)
var bmd:BitmapData = new BitmapData(200,200,false,0xFFCC00);
var data:ByteArray = new PNGEncoder().encode(bmd);
var enc:Base64Encoder = new Base64Encoder();
enc.encodeBytes(data);
//得られた値をURIスキーマに付け加える
var s:String = "'jpCirueloGetter://arg1=" + getEncodedBMPData(bmd) +
"'";
return s;
}
//base64エンコードした文字列をパラメータとして持つURIスキーマをaタグに埋め込んで表示
var wv:StageWebView = new StageWebView();
var rect:Rectangle = new Rectangle(0,0,480,300);
wv.viewPort = rect;
wv.stage = stage;
var xml:XML =
<html>
<body>
<a href = {createURI()}>URIスキーマを利用して起動</a>
</body>
</html>
wv.loadString(xml.toXMLString());
こんな感じですね。
あとは、受け取る側のinvokeイベントに割り当てた関数以内で、この値をパースして
デコードする仕組みを作ってあげればOKです。
デコードする場合には、mx.utils.Base64Decoderを使用します。
ちょっと雑ですが、こんな感じで
function onInvoke(e:InvokeEvent){
//起動時に渡されたパラメータから、必要な部分だけを切り出す
var uri:String = "testApp://arg1="
var s:String = e.arguments[0].toString().substr(uri.length);
//base64でコード
var dec:Base64Decoder = new Base64Decoder();
dec.decode(s);
var ba:ByteArray = dec.toByteArray();
//得られたバイナリデータ(今回はPNGファイル)を画面に表示
var loader:Loader = new Loader();
addChild(loader)
loader.loadBytes(ba);
}
と、こんな感じでbase64エンコード/デコードを経由すれば、バイナリデータの受け渡しも
可能でした。
ただ、あまり大きなデータは、URIスキーマのパラメータが長すぎるのか、コケてしまう事も
ありました。画像データで言うと、形式にもよりますけど、画面全体のスクリーンショットを
送ろうとしたら、コケました。
これは、エラーログを見る限り、AIR for Android的な限界というよりも、Android的な限界
なのかなあ、という感じです。
Javaで作成したアプリからAIRアプリへとURIスキーマ経由で大きなデータを渡そうとした場合
にも、おそらくコケるんじゃないかな?と思います。
ちょっとしたテキストデータや、それほど大きくないバイナリデータの受け渡しは、
かなりスムースにいけますよ。
■まとめ
URIスキーマを使えば、ブラウザ経由でアプリ間のちょっとした連携ができそうです。
AIRアプリ同士だけでなく、Javaで作成したAndroidアプリとデータをやり取りしたい場合にも
利用できそうなので、複数の小さなアプリを用途に応じて組み合わせて使用したい場合等に
便利そうですね。
ではでは。
---
シルエロ:吉岡梅
umeyo...@gmail.com