Web Activitiesのメモ@Firefox OS

Firefox OSのWeb Activitiesを軽く確認したのでメモ。
全体を追うと、Web Activitiesでアプリを呼び出す側と呼び出される側の実装について一通りの流れは掴めるかと思います。

Web Activitiesとは何か

Web ActivitiesはMozillaさんの「WebAPI」の一つで、Webの世界におけるアプリ連携の仕組みです。
今のところはMozillaの独自規格です。

AndroidにおけるIntentのようなものです。
Firefox OSでは、このWeb Activitiesを使ってアプリ同士を連携させます。

Web標準の世界(とGoogle)で言えばWeb Intentsみたいなもの、というかhttps://wiki.mozilla.org/WebAPI/WebActivitiesのIntroductionで「Web Activities is a counter-proposal to Web Intents.」と陽に対抗仕様であることが謳われています。

Web Intentsは以前Google Chromeに実装されていて、Chrome 24で一旦削除されましたが、そのうち帰ってくるらしいです。
(とか書いていたらtwitter経由で死亡通知が流れてきたよママン……https://twitter.com/ourmaninjapan/status/337193238417006592

(その後)
Web Intentsの「Working Draft」は、2013/05/23付けで「Working Group Note」に変更されていました。
南無南無。
https://dvcs.w3.org/hg/web-intents/raw-file/tip/spec/Overview.html

Web Activiiesのリファレンス

Firefox OSに特化した仕様ではありませんが、以下のリンク先になります。

https://developer.mozilla.org/ja/docs/WebAPI/Web_Activities

アプリの呼び出し方(=Activityの発行の仕方)

呼び出す側、つまり自分が作ったアプリから他のアプリを呼び出す方法です。
Androidで言うとnew Intent()してパラメータを渡してstartActivity()(結果が必要な場合はstartActivityForResult())して……という一連の流れです。

Firefox OS(とWeb Activities)の「Activity」は、Androidの「Intent」に相当します。

Activityを初期化する

リファレンスのサンプコードを以下に示します。
このような感じでMozActivityを初期化します。

var activity = new MozActivity({
name: "pick",
data: {
type: "image/jpeg",
"image/png"
}
});

nameは、AndroidのIntentでのaction、つまり「やってほしいこと」に相当します。
Firefox OSのGaiaでは、例えば以下のような「name」が用意されています。
詳細はhttps://developer.mozilla.org/ja/docs/WebAPI/Web_Activitiesの「Firefox OS activities」節をご確認ください。

・pick(データを呼び出し先アプリから取ってくる)
・configure(Firefox OSの設定画面を呼び出す)
・dial(Firefox OSのもしもし画面を呼び出す)

dataは、呼び出し先アプリに渡すためのパラメータです。
上記例では「取ってくる画像のtypeは”image/jpeg”で」と宣言しています。
dataの中には複数のパラメータを指定することができ、また一つのパラメータに対して複数の値を与えることもできます。

Activityを発火する

AndroidにおけるstartActivity()相当の「キックする処理」はないようです。
Activityを初期化した瞬間にキックした瞬間に発火すると思います。
(この辺、以前仕様を確認したときからずっと謎なんですが)

結果を受け取る

呼び出し先のアプリから結果を受け取るには、初期化したMozActivityのonsuccessイベントハンドラを実装します。
結果は、onsuccessの中で「this.result」から取り出すことができます。
pickで呼び出し先アプリから画像を取得する場合、以下のように結果が格納されています。

・this.result.name(画像のパス)
・this.result.type(画像の型)
・this.result.blob(画像データ=メイン)

エラーを受け取る

呼び出し先からのエラーやキャンセルをハンドルしたい場合は、MozActivityのonerrorイベントハンドラを実装します。

・this.error(エラーオブジェクト/キャンセルした場合は確か空っぽ)

サンプルコード

以下に、リファレンスにある画像取得の例も含めてごく簡単なサンプルをつっこんでいます。
(Firefox OS SimulatorとKeonで動作確認)

https://github.com/kisato/WebActivitiesSample

アプリができること(=受付可能なActivity)の宣言

呼び出される側、つまり自分がどんな処理に対応しているか、どんなデータ形式に対応しているか等を宣言する方法です。
Androidで言うと、AndroidManifest.xmlのに相当します。

manifestファイルで静的に宣言する

これもリファレンスのサンプルコードのままですが、アプリのマニフェストファイルの中で「そのアプリが処理可能なActivity」を宣言します。


{
// Other App Manifest related stuff

// Activity registration
"activities": {
"pick": {
"href": "./pick.html",
"disposition": "inline",
"filters": {
"type": ["image/jpeg","image/png"]
},
"returnValue": true
}
}
}

この例では、以下のことを宣言しています。

・受け取れるActivityのnameは「pick」(同一マニフェストの中に複数種のActivityへの宣言が書ける)
・pickを受け取るURLは「./pick.html」(そのアプリの中で、どのURLがname=pickに対応するか)
・表示方法は「inline」(windowを指定すると別ウィンドウで、inlineを指定するとオーバーレイで表示)
 (……のはずなんだけど、「window」を指定すると動かなかった)
・処理対象となる型は「image/jpeg」か「image/png」(pickの場合は返却するデータのtype、のはず)
・返り値は「あり」

一つのアプリで、複数の処理(Activityのname)に対応することができます。
また同一のURL(href)が複数のnameに対応することも可能です。

navigator.registerContentHandlerやnavigator.registerProtocolHandlerで動的に宣言する

manifestファイルによる静的な宣言の他、JavaScriptでnavigatorオブジェクトのregisterContentHandlerをregisterProtocolHandlerを実行することで、動的に宣言することができます。
が、https://developer.mozilla.org/ja/docs/WebAPI/Web_Activitiesの「Register an activity」-「Dynamic registration」によると今のところ未対応のようです。

name毎の処理を記述する

Activity経由でアプリ(でhrefに指定されたURL)が呼び出された時の処理は、navigaterオブジェクトのmozSetMessageHandlerに記述します。
以下、リファレンスのサンプルからの引用です。


navigator.mozSetMessageHandler('activity', function(activityRequest) {
var option = activityRequest.source;

if (option.name === "pick") {
// Do something to handle the activity
}
});

mozSetMessageHandlerの第1引数に「activity(Web Activitiesに限れば固定文字列)」を、第2引数にfunction(ハンドラ)を指定します。
第2引数で与えるfunctionの引数に呼び出し元アプリからのActivityが(Firefox OSによって)渡されますので、必要に応じてnameやtype等を取り出して処理を記述します。

1つのhtmlで複数のnameに対応し、それらが異なる処理である場合は(普通そうだと思いますが)、ここで分岐を設ける必要があります。

結果を返す

呼び出し元アプリに処理結果を返す必要がある場合は、ハンドラの引数として渡されたActivityのpostResultを実行します。


navigator.mozSetMessageHandler('activity', function(activityRequest) {
var option = activityRequest.source;

if (option.name === "pick") {
// Do something to handle the activity
...

// Send back the result
if (picture) {
activityRequest.postResult(picture); // この辺
} else {
activityRequest.postError("Unable to provide a picture");
}
}
});

activityRequest.postResultを実行した瞬間に、このアプリ(呼び出し先アプリ)から制御が失われます。つまりpostResult以降に処理が書かれていたとしても、それは実行されません。

postResultの引数として入れた値(上記例ではpicture)は、Firefox OSを通じて呼び出し元アプリへ渡され、同時に呼び出し元アプリへ制御が戻ります。
そして、呼び出し元アプリの「activity.onsuccess()」の処理に入ります。

エラーを返す

エラーを返す場合は、postResultの代わりにpostErrorを実行します。
こちらも、実行した瞬間に呼び出し先アプリから制御が失われます。

まとめ

だいたいこんな感じです。

あと、普段Webアプリ作りに携わっていないせいか、嵌まった点がいくつかありましたのでメモ。

Gaia

冒頭近くでも書きましたが、Firefox OSの「がわ」の部分、GeckoエンジンとWebAPIの仲介をしてくれる人(のはず)です。
現物は以下のリンク先にあります。

https://github.com/mozilla-b2g/gaia

この中の「shared」をまるっと自分のアプリにコピーすると、スタイルシートや共通処理ライブラリを叩きやすいです。
また「apps」の下にはFirefox OSの組み込みアプリが入っているので、アプリを作る際の参考にはなると思います。

(数時間見ただけだと断片的にしか適用方法がわからなかったのと、入れるとコードがごちゃっとするので動作確認用のコードからは削りました)

innerHTML

activityの実行結果を画面に出そうとしてdiv.innerHTMLでテキストを突っ込もうとしたんですが、これってFirefox(ブラウザ)ではNGだったんですね。Firefox OSでも無反応でした。
今回試した限りでは、div.textContentを使えばOKでした。

manifestのactivitiesに「window」を指定すると表示されない

manifestファイルの中でアクティビティ呼び出し時の表示方法を指定する「disposition」はwindowとinlineから選択できます。
しかし、「”disposition”: “window”」を指定した場合は画面が遷移しませんでした。

一方、dispositionは省略可能で、省略時のデフォルトは「window」です。
(ということはつまり、明示的にwindowを指定した場合だけでなく、無指定の場合も遷移しない)
ですので、現時点では「”disposition”: “inline”」を明示的に記述するのが無難です。

# 何か仕様を見落としているかポカミスをやっている気もしますけど……

手探りで確認したので、誤った記述や動作があれば教えていただけると助かります。

コメントを残す

メールアドレスが公開されることはありません。

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください