BTSSPを自力で作る~Android BeamからのBluetooth通信~

こんにちは、あなたのヒーロー東野です。

前回は「Android Beamおもしろいけどプログラミングしてもあまり利便性がないね」というお話をしました。

前回の記事:「意外と知られていない!? Android Beam(アンドロイドビーム)っていうAirDropみたいな機能のご紹介。(サンプルソースあり)」

その過程でBTSSPというものをご紹介しましたが、
今回はそのBTSSPを自力で作って双方向通信出来るまでを実装していきたいと思います。

双方向通信にはBluetoothを使います。
Bluetooth通信の実装方法から見ていきましょう。

Bluetooth通信の実装

ペアリング

Bluetoothは送受信する端末を「ペアリング」しないと通信出来ないという前提があります。
双方の端末の設定からBluetoothを選択します。
bluetooth1
どちらでも構わないので、
端末を探す側は①を
探してもらう側は②をタップしてください。
そうすると①側には見つかった端末の一覧が表示されるので、ペアリングしたい端末を選択します。
両端末にペアリングのリクエストが来るので、両方が「OK」を選択してペアリングが完了します。
bluetooth3
bluetooth2
ここまでがBluetooth通信をする準備です、面倒ですね。

Bluetooth接続の実装

BluetoothのプログラミングはAndroid公式のサンプルソースにBluetoothChatというものがあるので、それを流用すればすぐに作る事が出来ます。

送信側、受信側アプリのマニフェストファイルにBluetoothを追加します



サンプルソースBluetoothChatの中からChatManager.javaを取り出し、送信側、受信側アプリに組み込みます。

ChatManager.javaの先頭の方に

private static final UUID MY_UUID = UUID.fromString("fa87c0d0-afac-11de-8a39-0800200c9a77");

とありますが、このUUIDはサンプルソース用のUUIDです。
同じUUIDを使ったもの同士が通信出来る仕様なので変更する必要があります。
誰とでも通信が出来る一意なUUIDに変更します。

private static final UUID MY_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");

と書き換えます。
このUUIDを使ったBluetooth通信はSSPと呼ばれるものですが、今回は説明を省きます。

送信側アプリのActivity、受信側アプリのActivityそれぞれからChatManagerにHandlerをセットします。

chatManager=new ChatManager(handler);
if (chatManager.getState()==ChatManager.STATE_NONE) {
	chatManager.start();
}

private final Handler handler=new Handler() {
	@Override
	public void handleMessage(Message msg) {
		if (msg.what==MSG_STATE_CHANGE) {
			switch (msg.arg1) {
				case ChatManager.STATE_CONNECTED:
					Toast.makeText(RecvActivity.this, "接続完了", Toast.LENGTH_SHORT).show();
					break;
				case ChatManager.STATE_CONNECTING:
					break;
				case ChatManager.STATE_LISTEN:
				case ChatManager.STATE_NONE:
					Toast.makeText(RecvActivity.this, "未接続", Toast.LENGTH_SHORT).show();
					break;
			}
			//メッセージ受信
		} else if (msg.what==MSG_READ ){
			byte[] rcvData = (byte[])msg.obj;
			int rcvLength = msg.arg1;
			String rcvMsg = new String(rcvData,0,rcvLength));
		}
	}
};

ChatManagerの中には接続スレッド送信用スレッド受信用スレッドなど必要なものがすべて入っています。
ChatManagerで受信したメッセージはセットしたActivityのHandlerに返ってきます。

送信側Activity

mBtAdapter = BluetoothAdapter.getDefaultAdapter();

Set pairedDevices = mBtAdapter.getBondedDevices();
for (BluetoothDevice device : pairedDevices) {
	String deviceName = device.getName();
	String deviceAddress = device.getAddress();
}

BluetoothAdapterから取得したpairedDevicesにはペアリングした端末一覧が取得出来ます。
deviceNameには端末名が、
deviceAddressには対向のMACアドレスが入ります。
接続するにはこのMACアドレスを使います。

chatManager.connect(btAdapter.getRemoteDevice(deviceAddress));

これで接続が開始されます。

接続が完了すると送信側アプリのActivity、受信側アプリのActivityそれぞれのHandlerに接続完了の通知が来ます。
これで双方向通信が確立されました。

Bluetooth通信の送信プログラミング

String string = "テスト";
byte[] byteData = string.getBytes();
chatManager.write(byteData);

chatManagerにバイトデータをwriteすると送信されます。
受信側はrcvDataにデータが入ります。
取り出した文字列”テスト”はrcvMsgに入ります。

ここまでがBluetoothの接続に必要な最低限の実装です。
長かった…、手順が多いですよね。
送信側も受信側もアプリが起動している必要があるし、とても非効率的です。

ここで役に立つのがAndroid Beamです。

そもそも通信とは何でしょう?
ホストネームがあり、IPアドレスがあり、そして最後にはMACアドレスがある。
最終的には相手のMACアドレスと自分のMACアドレスを繋ぐものが通信であり、それはBluetoothも同じです。

自分のMACアドレス(文字列)をAndroid Beamで相手の端末に伝え、
Android Beamを受信した端末は送られてきたMACアドレスに対して接続をすれば接続先を選ぶ手間がいりません。

bluetooth4
しかも受信側はAndroid Beamを契機にアプリが起動するので一石二鳥です。

Android BeamからBluetooth双方向通信開始までの実装

送信側アプリのActivity、受信側アプリのActivityそれぞれからChatManagerにHandlerをセットします。

chatManager=new ChatManager(handler);
if (chatManager.getState()==ChatManager.STATE_NONE) {
	chatManager.start();
}

ここまでは一緒です。

送信側Activityは自分のBluetoothのMACアドレスを取得し、Android Beamで送信します。

	@Override
	public NdefMessage createNdefMessage(NfcEvent event) {
		if (chatManager.getState()==ChatManager.STATE_NONE) {
			chatManager.start();
		}
		btAdapter=BluetoothAdapter.getDefaultAdapter();
		String address =  btAdapter.getAddress();
		NdefMessage msg = new NdefMessage(new NdefRecord[] {
			createMimeRecord("application/com.example.airdroptest", address.getBytes()),
		});
		return msg;
	}

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

自分のBluetooth MACアドレスはBluetoothAdapter.getAddress()

で取得出来ます。
この文字列を送るだけです。

受信側は取り出した文字列=MACアドレスに対し、chatManager.connect()をセットします。

	@Override
	public synchronized void onResume() {
		super.onResume();
		if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(getIntent().getAction())) {
			Parcelable[] rawMsgs = intent.getParcelableArrayExtra( NfcAdapter.EXTRA_NDEF_MESSAGES);
			NdefMessage msg = (NdefMessage) rawMsgs[0];
			String address = new String(msg.getRecords()[0].getPayload());
			chatManager.connect(btAdapter.getRemoteDevice(address));
		}
	}

これだけでBluetoothの双方向通信が確立します。
接続完了後はどちらからもメッセージを送る事が出来ます。
通信速度も申し分ないため、画像やファイルをバイトデータに変換して送るのも自由です。

Android BeamとBluetoothはそれぞれでは非常に不便ですが、
組み合わせる事によって通信確率までのユーザビリティが非常に楽になります。
※ちなみに今回の実装ではBluetoothのペアリングは必須です。

非接触通信は使い方によって、新しいサービスに繋がり得る可能性を持っています。
違う技術同士を組み合わせる事で新しい発見に繋がるのはおもしろいですねフフフフフフ

コメントを残す

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