AndroidBeamを使用してデータを送信する


Android4.0(以降ICS)からAndroidBeamという機能が搭載されました。これはNFCチップを搭載するAndroid端末同士でデータを交換する仕組みです。

この機能を使用すると端末間のデータの交換が容易に可能になります。

今回はAndoid Developerサイト内の”Beaming NDEF Messages to Other Devices“のソースコードを元に解説していきます。

このサンプルはAndroidBeamを実装するために必要な実装が入っているため非常に参考になるサンプルです。

詳細は以下から。

AndroidBeamデータを送信するためには以下の手順が必要になります。

  1. マニフェストファイルへNFCのパーミッションを追加する
  2. NFCチップの制御用インスタンスを取得する
  3. 送信メッセージ作成用インターフェイスを実装する
  4. NFCチップの制御用インスタンスと送信メッセージ作成用インターフェイスを関連付ける
  5. データを受け取る処理を実装する
  6. データを受信する先を設定するためのintentfilterを追加する

マニフェストファイルへNFCのパーミッションを追加する

NFCでデータを送信する場合にはAndroidManifest.xmlに“android.permission.NFC”を追加する必要があります。

NFCチップの制御用インスタンスを取得する

NFCチップの制御をするためにはNfcAdapterクラスのインスタンスを取得します。

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        TextView textView = (TextView) findViewById(R.id.textView);
        // Check for available NFC Adapter
        mNfcAdapter = NfcAdapter.getDefaultAdapter(this);
        if (mNfcAdapter == null) {
            Toast.makeText(this, "NFC is not available", Toast.LENGTH_LONG).show();
            finish();
            return;
        }
        // Register callback
        mNfcAdapter.setNdefPushMessageCallback(this, this);
    }

NfcAdapterクラスのインスタンスはNfcAdapter#getDefaultAdapterメソッドを使用して取得します(ソースコード内7行目)。

このメソッドの戻り値がnullの場合はNFCチップが搭載されていないため、アプリを終了させるなどの処理が必要になります(ソースコード内8~12行目)。

送信メッセージ作成用インターフェイスを実装する

AndroidBeamで送信するデータはCreateNdefMessageCallback#createNdefMessageメソッド内で作成します。

このメソッドはCreateNdefMessageCallbackインターフェイスのメソッドですので、まずはCreateNdefMessageCallbackインターフェイスをimplementsする必要があります。

    @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())
         /**
          * The Android Application Record (AAR) is commented out. When a device
          * receives a push with an AAR in it, the application specified in the AAR
          * is guaranteed to run. The AAR overrides the tag dispatch system.
          * You can add it back in to guarantee that this
          * activity starts when receiving a beamed message. For now, this code
          * uses the tag dispatch system.
          */
          //,NdefRecord.createApplicationRecord("com.example.android.beam")
        });
        return msg;
    }

createNdefMessageメソッド内ではNFCで送信するデータであるNdefMessageクラスのインスタンスを作成しています(ソースコード内5~7行目)。

NdefMessageクラスには複数のNdefRecordクラスのインスタンスを格納することができ、送信するデータの実体はNdefRecordクラスのインスタンスに格納します。

GoogleのサンプルではNdefRecordを作成するための独自メソッドが記述されています(上記コード6行目で使用されているcreateMimeRecordメソッド)。

以下はcreateMimeRecordメソッドの実装部分です。

    /**
     * Creates a custom MIME type encapsulated in an NDEF record
     */
    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;
    }

NdefRecordクラスのインスタンスには以下の内容を格納します。

[table “143” not found /]

上の表に示したデータはNdefRecordクラスのコンストラクタで設定します(createMimeRecordメソッド内6、7行目)。

NFCチップの制御用インスタンスと送信メッセージ作成用インターフェイスを関連付ける

CreateNdefMessageCallbackインターフェイスが実装されているクラスをNfcAdapterクラスインスタンスに設定します。

これにはNfcAdapter#setNdefPushMessageCallbackメソッドを使用します。

    @Override
    public void onCreate(Bundle savedInstanceState) {
~省略~
        // Register callback
        mNfcAdapter.setNdefPushMessageCallback(this, this);
    }

データを受け取る処理をonResumeに実装する

AndroidBeamで送信されたデータはintentを通して受信します。

データの実体を取得するためには以下の手順が必要です。

  • intentからNdefMessageクラスインスタンスを取得する
  • NdefMessageクラスインスタンスからNdefRecordクラスインスタンスを取得する
  • NdefRecordクラスインスタンスからデータを取得する
    @Override
    public void onResume() {
        super.onResume();
        // Check to see that the Activity started due to an Android Beam
        if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(getIntent().getAction())) {
            processIntent(getIntent());
        }
    }

~省略~

    /**
     * Parses the NDEF Message from the intent and prints to the TextView
     */
    void processIntent(Intent intent) {
        textView = (TextView) findViewById(R.id.textView);
        Parcelable[] rawMsgs = intent.getParcelableArrayExtra(
                NfcAdapter.EXTRA_NDEF_MESSAGES);
        // only one message sent during the beam
        NdefMessage msg = (NdefMessage) rawMsgs[0];
        // record 0 contains the MIME type, record 1 is the AAR, if present
        textView.setText(new String(msg.getRecords()[0].getPayload()));
    }

intentからNdefMessageクラスインスタンスを取得する
intentからNdefMessageクラスインスタンスを取得するにはIntent#getParcelableArrayExtraメソッドで、NfcAdapter.EXTRA_NDEF_MESSAGESを引数で渡すことで取得できます(ソースコード内17、18行目)。

NdefMessageクラスインスタンスからNdefRecordクラスインスタンスを取得する
NdefMessageクラスインスタンスからNdefRecordクラスインスタンスを取得するにはNdefMessage#getRecordsメソッドでNdefRecordクラスの配列を取得し、配列の要素番号を指定して取得します(ソースコード内22行目)。

NdefRecordクラスインスタンスからデータを取得する
NdefRecordクラスインスタンスに対してNdefRecord#getPayloadメソッドを使用することでデータの実体を取得します(ソースコード内22行目)。

データを受信する先を設定するためのintentfilterを追加する

AndroidBeamでデータを受け取りたいActivityのintentfilterに対して以下を追加する必要があります。

<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>

以上長々とお疲れ様でした。

関連する記事: