Android Beam の基本

この記事は Android Developers サイトAndroid 4.0 Platform の一部及び NFC Basics/Beaming NDEF Messages to Other Devices の翻訳をまとめたものです。

Android Beam とは

Android Beam は NFC ベースの機能で、NFC が利用可能な携帯端末を重ねることによって、ユーザが使用しているアプリに関する情報を即座に共有する機能です。範囲内にデバイスが存在する時ー数センチメートル以内でーシステムは NFC 接続を準備し、共有のための UI を表示します。見ている何かを他のデバイスと共有するには、ユーザはスクリーンをただタッチするだけです。

開発者にとって、Android Beam は殆ど全てのタイプの、接近に基づいたインタラクションを引き起こす新しい方法です。例えば、ユーザは連絡帳を即座に交換、マルチプレイヤーのゲームのセットアップ、チャットやテレビ電話への参加、写真やビデオの共有、などを行うことができます。システムは低レベルの NFC サポートと 共有のUI を提供する一方、フォアグラウンドのアプリは他のデバイスに転送するための軽量のデータを提供します。開発者は共有されるデータとそれがどのように取り扱われるかについて、完全に制御しているため、殆どのインタラクションが可能です。
もっと大きなペイロードについては、Android Beam を初回の接続として利用し、ユーザがペアリングを意識する必要なくBluetooth経由でデータを転送することができます。

開発者が Android Beam に基づくインタラクションに手を加えなくても、Android の中に深く統合された利益を享受することができる場合があります。デフォルトではシステムは アプリケーションの Android Market のURL を共有します。そのため、ユーザはすぐにアプリケーションのダウンロードまたは購入することが簡単にできます。

Android Beam (NDEF Push with NFC)の仕組み

Android Beam は あるデバイスから他へ NDEF メッセージを送信すること(この処理は "NDEFプッシュ" としても知られています)を可能とする新しい NFC の機能です。Android Beam をサポートする2台の Androidバイスが隣接(約4cm)し、通常は背面同士がタッチしている時、データ転送は初期化されます。NDEF メッセージの中のデータは、デバイス間で共有したいデータを含むことができます。例えば、連絡帳の共有、YouTubeの共有ビデオ、ブラウザによるURLの共有を行うアプリは Android Beam を使えます。
Android Beam を使ったデバイス間のデータの送信には、アクティビティがフォアグラウンドにある間に、共有したい情報を含む NdefMessage を生成する必要があります。次の2つの方法のうちのいずれかでシステムに対して NdefMessage を渡す必要があります:

  • アクティビティ中でプッシュする 単一の NdefMessage の定義:
    • メッセージを送りたい時に都度 setNdefPushMessage() を呼び出します。例えば、おそらく、アクティビティの onCreate() メソッドでこのメソッドを呼び出して、NdefMessage を渡すことでしょう。アクティビティがフォアグラウンドにいる間、 Android Beam が他のデバイスから活性化される場合は常に、システムは NdefMessage を他のデバイスに送信します。
  • Android Beam の初期化と同時にプッシュする NdefMessage の定義:
    • 送りたい NdefMessage を返す createNdefMessage() メソッドの実装中に、NfcAdapter.CreateNdefMessageCallback を実装する。その時、NfcAdapter.CreateNdefMessageCallback を setNdefPushMessageCallback() の実装へ渡します。
    • このケースではアクティビティがフォアグラウンドにある間、他のデバイスから活性化された時、システムは送りたい NdefMessage を引き出すために createNdefMessage() を呼び出します。これは、メッセージのコンテンツがアクティビティの存在中に終始変化するかもしれないケースにおいて、初期化された Android Beam を一度だけ配信するために NdefMessage を定義することを許します。

システムによって他のデバイスへの NDEF メッセージの送信に成功した際に、特定のコードを処理したい場合は、NfcAdapter.OnNdefPushCompleteCallback を実装し、setNdefPushCompleteCallback() でセットすることができます。メッセージが配信された時、システムは onNdefPushComplete() を呼び出すでしょう。

バイスの受信時、通常の NFC タグと同等の方法で NDEF プッシュメッセージを処理します。
システムはアクティビティを開始するために、ACTION_NDEF_DISCOVERED アクションとNdefMessage の 最初の NdefRecord に従って URL か MIME タイプのいずれかを設定して、インテントを起動します。アクティビティで反応させるために、対応したい URL か MIME タイプのインテントフィルタを定義することができます。詳細は NFC 開発者ガイドの Tag の処理についてを参照して下さい。

URL を NdefMessage で送りたい場合、文字列か Uri オブジェクトを元とした新しい NdefRecord を作成する createUri という便利なメソッドを使うことができます。URI が、Android Beam のイベント中受信するアプリケーションが特別なフォーマットであるという場合、送られてくる NDEF メッセージを受信するために、同一の URI スキームを使用するアクティビティのためのインテントフィルタを生成すべきです。

例え他のアプリケーションが同じインテントアクションをフィルタを処理するとしても、入ってくる NDEF メッセージをアプリケーションが処理することを保証するためには、NdefMessage と共に“Android アプリケーションレコード" も渡すようにすべきです。createApplicationRecord() を呼び出すことで Android アプリケーションレコード を生成することができ、アプリケーションのパッケージ名を渡すことができます。アプリケーションレコードと、特定のインテントを処理するアクティビティを含む複数のアプリケーションを伴う NDEF メッセージを他のデバイスで他のデバイスが受信した時、システムはいつも(アプリケーションレコードにマッチしたものに基づいた)アプリケーション中のアクティビティにメッセージを配信します。その際、ターゲットのデバイスにアプリケーションがインストールされていない場合、システムは Android マーケットを起動してユーザにアプリケーションをインストールさせるために Android application record を用います。

アプリケーションが NDEF プッシュメッセージを行うのに NFC API を使わない場合、その時は Android は標準の振る舞いを行います:あるデバイスのアプリケーションがフォアグラウンドにあり、他の Androidバイスから Android Beam が起動される時、他のデバイスAndroid アプリケーションレコードとアプリケーションのID を含む NDEF メッセージを受信します。受信したデバイスにアプリケーションが既にインストールされている場合、システムはそれを起動します。インストールされていない場合は、Android マーケットが開き、インストールするためにユーザを案内します。

Android Beam と その他の NFC の機能について、NFC 基本 開発者ガイドを読むことができます。Android Beam を使ったサンプルコードは Android Beam デモを御覧ください。

Android Beam の詳細

Android Beam は、2つのAndroidバイス間でシンプルなピア・ツー・ピアデータ交換を可能にします。他のデバイスへデータを送りたいアプリケーションは、フォアグラウンドにいて、且つ、データを受信するデバイスがロックされていないことが必要です。受信側のデバイス接触するぐらい十分に送信するデバイスを近づけると、送信側のディスプレイに "Touch to Beam" UIが表示されます。ユーザーは受信側のデバイスにメッセージを受信するかどうかを選択することができます。

注意:フォアグラウンド NDEF プッシングは API レベル10から使用可能で、Android Beam と同様の機能を有します。これらの API 群は非推奨となりましたが、旧デバイスをサポートすることが可能です。詳細はenableForegroundNdefPush() をご覧下さい。

アプリケーションで Android Beam を有効にするために、次の2つのメソッドのうちいずれかを使用できます:

  • setNdefPushMessage(): 送信するメッセージをセットするためのNdefMessage を受け入れます。2つのデバイスが十分近くに隣接すると自動的にメッセージを送信します。
  • setNdefPushMessageCallback():送信範囲内にデバイスが存在する時に呼び出されるcreateNdefMessage() を含むコールバックを受け入れます。コールバックは必要な時に限って、NDEF メッセージを生成させます。

アクティビティは、1度に1つの NDEF メッセージのみをプッシュすることが可能です。そのため、両方がセットされている時は、setNdefPushMessageCallback()setNdefPushMessage() よりも優先されます。

Android Beam を使うためには、下記の一般的なガイドラインに従う必要があります:

  • データを送信するアクティビティはフォアグラウンドにある必要があります。両デバイス共にスクリーンはアンロック状態である必要があります。
  • NdefMessage オブジェクトに送信したいデータをカプセル化する必要があります。
  • 送信されたデータを受信するNFCバイスは、com.android.npp NDEF push protocol か、NFC フォーラムの SNEP(Simple NDEF Exchange Protocol) のいずれかをサポートする必要があります。com.android.npp プロトコルAPI レベル9 (Android 2.3) から API レベル13 (Android 3.2) のデバイスが必要です。com.android.npp と SNEP の両方は API レベル14 (Android 4.0) 以降が必要です。

注意:Android Beam が使用可能なアクティビティがフォアグラウンドにある場合、標準的なインテントの処理は無効となります。しかし、アクティビティがフォアグラウンドで処理することもまた有効である場合、フォアグラウンド処理中にインテントフィルタにマッチするタグを引き続きスキャンする事ができます。

Android Beam を有効にするために:

  1. 他のデバイスへプッシュしたい NdefRecords を含んだ NdefMessage を生成します。
  2. NdefMessage を含む setNdefPushMessage() を呼び出すか、アクティビティ中の onCreate() メソッドの中で NfcAdapter.CreateNdefMessageCallback オブジェクトが渡された setNdefPushMessageCallback を呼び出します。これらのメソッドは、活性化したい他のアクティビティのオプションのリストと共に、 Android Beam で有効にしたいアクティビティが少なくとも1つは必要です。

一般に、2つのデバイスがコミュニケーションする範囲内にある場合、アクティビティがいつも同じ NDEF メッセージをプッシュする必要があるだけである場合は、通常 setNdefPushMessage() を使います。アプリケーションが現在のアプリケーションのコンテキストを扱いたい時やユーザがアプリケーションに対して行っていることに依存する NDEF メッセージをプッシュしたい時は、setNdefPushMessageCallback を使います。

以下は アクティビティの onCreate() メソッド中で、NfcAdapter.CreateNdefMessageCallback を呼び出す単純なアクティビティをどのように実装するかの例です(完全なサンプルを御覧ください)。この例はまた MIME レコードの作り方も示しています:

package com.example.android.beam;

import android.app.Activity;
import android.content.Intent;
import android.nfc.NdefMessage;
import android.nfc.NdefRecord;
import android.nfc.NfcAdapter;
import android.nfc.NfcAdapter.CreateNdefMessageCallback;
import android.nfc.NfcEvent;
import android.os.Bundle;
import android.os.Parcelable;
import android.widget.TextView;
import android.widget.Toast;
import java.nio.charset.Charset;


public class Beam extends Activity implements CreateNdefMessageCallback {
    NfcAdapter mNfcAdapter;
    TextView textView;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        TextView textView = (TextView) findViewById(R.id.textView);
        // 利用可能なNFC アダプタのチェック
        mNfcAdapter = NfcAdapter.getDefaultAdapter(this);
        if (mNfcAdapter == null) {
            Toast.makeText(this, "NFC is not available", Toast.LENGTH_LONG).show();
            finish();
            return;
        }
        // コールバックを登録する
        mNfcAdapter.setNdefPushMessageCallback(this, this);
    }

    @Override
    public NdefMessage createNdefMessage(NfcEvent event) {
        String text = ("Beam me up, Android!\n\n" +
                "Beam Time: " + System.currentTimeMillis());
        NdefMessage msg = new NdefMessage(
                new NdefRecord[] { createMimeRecord(
                        "application/com.example.android.beam", text.getBytes())
          /**
          * Android Application Record(AAR)はコメントアウトされています。
          * デバイスがAARを含むプッシュを受信した時、アプリケーションは
          * 実行を保証するためにAARを指定します。AARはタグの処理システムをオーバーライドします。
          * メッセージを受信した時にこのアクティビティが開始されることを保証するために、
          * 後ろに追加することができます。今のところ、このコードはタグ処理
          * システムを使っています。
          */
          //,NdefRecord.createApplicationRecord("com.example.android.beam")
        });
        return msg;
    }

    @Override
    public void onResume() {
        super.onResume();
        // アクティビティがAndroid Beamによって開始されたことをチェックする
        if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(getIntent().getAction())) {
            processIntent(getIntent());
        }
    }

    @Override
    public void onNewIntent(Intent intent) {
        // インテントを処理するために、この後でonResumeが呼ばれる
        setIntent(intent);
    }

    /**
     * インテントからのNDEFメッセージのパースとTextViewへの表示
     */
    void processIntent(Intent intent) {
        textView = (TextView) findViewById(R.id.textView);
        Parcelable[] rawMsgs = intent.getParcelableArrayExtra(
                NfcAdapter.EXTRA_NDEF_MESSAGES);
        // ビームの送信中は一つだけのメッセージ
        NdefMessage msg = (NdefMessage) rawMsgs[0];
        // 現在は、レコード0はMIMEタイプを含む、レコード1はAARを含む
        textView.setText(new String(msg.getRecords()[0].getPayload()));
    }

    /**
     * NDEFレコード内にカスタムMIMEタイプをカプセル化して生成する
     */
    public NdefRecord createMimeRecord(String mimeType, byte[] payload) {
        byte[] mimeBytes = mimeType.getBytes(Charset.forName("US-ASCII"));
        NdefRecord mimeRecord = new NdefRecord(
                NdefRecord.TNF_MIME_MEDIA, mimeBytes, new byte[0], payload);
        return mimeRecord;
    }
}

このコードはAARをコメントアウトしていますが、除去できることに注意して下さい。AARを有効にした場合、AAR中の特定のアプリケーションは常にAndroid Beam メッセージを受信します。アプリケーションが存在しない場合、Android Market がアプリケーションをダウンロードするために起動します。したがって、AAR が使われる場合、下記のインテントフィルタは Android 4.0 以降のデバイスでは技術的に必要ありません:

<intent-filter>
  <action android:name="android.nfc.action.NDEF_DISCOVERED"/>
  <category android:name="android.intent.category.DEFAULT"/>
  <data android:mimeType="application/com.example.android.beam"/>
</intent-filter>

このインテントフィルタにより、 com.example.android.beam アプリケーションが NFC タグをスキャンした時やcom.example.android.beam 型のAARを伴うAndroid Beamを受信した時、または、NDEF フォーマットのメッセージが application/com.example.android.beam 型の MIME レコードを含んでいる時に、開始することができます。

例え AAR がアプリケーションの開始とダウンロードを保証していても、インテントフィルタは推奨されます。何故なら、AAR によって特定されたパッケージの範囲内にあるメインのアクティビティを常に開始する代わりに、アプリケーション中の開始するアクティビティを選択する余地を与えるためです。AAR はアクティビティレベルの保証は行いません。また、いくつかの Android 端末は AAR をサポートしないため、万が一のために、NDEF メッセージの最初の NDEF レコードに、IDの情報を埋め込み、同様にフィルターすべきです。レコードの生成方法に関する詳しい情報は、NDEF レコードの共通タイプの作成を御覧ください。

文責:技術部 瀬戸 直喜