ひつじのにっき

mhidakaのにっきです。たまに長文、気が向いたとき更新。

Android 4.1(JellyBean)のAndroid Beamを使ってみたよ


データ交換アプリケーション「JCBeam」をアップデートする際に、JellyBeanのAndroid Beamの機能を使ってみました。
Android Beamそのものの使い方はtechbooster.orgのほうで解説する予定なので、ここではJCBeamというアプリケーションに利用する上で思ったこと、使い勝手とか書きます。

ソースコードgithubで公開しています。
https://github.com/mhidaka/JCBeam
参考になるところ,ならないところあると思いますが興味がある方は見てください。
注意:setBeamPushUrisで設定できるURIfileスキーマを使った場合、日本語ファイルには対応できてません。OSの制限だと思います。ASCIIコードでないと受信時にエラーとなるので注意してください。

Android 4.1でBeamは変わったの?

JellyBeanのAndroid Beamでは簡単に写真やビデオを共有できるのが特徴です。

  • ICSのBeam:NFC機能を使って単純な文字列(URLなど)やIntentを発行する
  • JBのBeam:NFC機能+大きいコンテンツはBluetoothで送信

という具合にNFCをファーストコネクションに利用して使い勝手を向上させています。本来、Bluetoothを使うにはペアリングが必要なのですが、その部分をNFCを使って省略することで上手く回避しています(ゼロ・コンフィギュレーションっていいます)。案外、初期設定のコストって大きいので、そこをスキップできるっていうのは高得点なのです。無線ルーターの設定を思い浮かべてもらうとわかりやすいです。

アプリにはどんな風に利用出来るの?

JCBeamはJCROMのテーマチェンジャーです。大きな画像ファイルなどがあるのでコンテンツの共有には便利です。

前回のICS版までは、NFCWiFi Directを利用して実装していました。
交換したいユーザ同士が、最初にNFCWiFi Directの初期設定を伝えて→WiFi Directで通信する。という二段のStepをふんで動きます。

今回のJB版では、Android BeamがNFCからBluetoothに通信経路を繋いでくれるのでそれに乗っかりました。WiFi Directの不安定さが半端ない、というのも原因です。Android 4.xのWiFi Directはすぐリブートする…。

思ったこと

現在のAndroid Beamは使い勝手の良い面、悪い面、両方あり、用途を選ぶというのが率直な感想
よく仕様を確認していくと、

4.1版Beamの実装となるNfcAdapter#setBeamPushUrisメソッドのリファレンスあたりに書いているのですが

  • NdefMessageとsetBeamPushUriは共存できない。
  • setBeamPushUriの受け取りはアプリじゃなくてAndroid OS。

[リファレンス]
http://developer.android.com/reference/android/nfc/NfcAdapter.html#setBeamPushUris(android.net.Uri[], android.app.Activity)

というのがシンプルさを提供すると共にネックになってると感じました。
ICS版まで使えたNdefMessageと排他(setBeamPushUriが優先される)という挙動になっているので細かい制御ができなくなってます。Bluetoothを使ってまで送りたい大きなコンテンツに紐付いたparameterが一切渡せないからです。

setBeamPushUrisメソッドで送れるコンテンツもfileスキーマかcontentスキーマURIのみなので、スキーマを利用して受け取りできるアプリを指定するのも難しい感じ(ExtraDataで何かいれられるのかな?未確認…)
受信側では一度Android OSが受け取り、開く際にandroid.intent.action.VIEWします。

09-17 20:40:36.383: W/ActivityManager(349): startActivity called from non-Activity context; forcing Intent.FLAG_ACTIVITY_NEW_TASK
for: Intent { act=android.intent.action.VIEW dat=file:///storage/sdcard0/beam/ANDROID.zip
typ=application/zip cmp=com.google.android.inputmethod.japanese/.userdictionary.UserDictionaryToolActivity bnds=[103,68][697,153] }

こんなかんじです。URI複数を一括して送受信できるんですが、これも受信時には" If multiple URIs are sent, the Intent will refer to the first of the stored files."とあったので配列の最初を参照して、Intent飛ばします、ということらしいです。
typeだけは拡張子から自動的に判断されるのでインテントフィルタを書けばなんとかなります。

インテントフィルタ例





mineTypeでapplication/zipを指定するとインテントを受けられます。

まとめ


向いているもの
  • 写真、動画、アプリケーションに依存しないコンテンツの共有
  • 最終生成物として楽しむ分には大丈夫
向いていないもの
  • アプリの中間生成ファイルみたいなコンテンツ共有者を限定するデータ
  • 巨大データ。BluetoothのOPPを使ってるのでWiFi Direct等より遅いです。
  • 送受信制御が必要なもの。相手に応じて動きを変えようとしても、NdefMessageなどが排他なので手段ない感じ。
  • あと○分です。って終了時間を通知できない。なので送信失敗しても困らないものじゃないと辛い(大きいデータほど失敗するし、Bleutoothの届く距離にいないといけない。再送制御もない)

というわけでJB版Android Beamをつかってもアプリケーションに誘導できる、アプリの価値を高めるっていう感じにはならない気がします。写真や動画でちゃんと出力するアプリならすでに対応済みでしょうし、そういうコンテンツをAndroid Beamを通してユーザ同士交換しよう、という使い方が一番しっくりきます。
ちょっと思ってるよりユースケースは狭いのでした。特長を生かした使い方をできるか、ですね。