こんにちは、ゴールデンウィークは引きこもって大好きな映画を見ていたmanaです。
今回は、AndroidとiOSを使用して、Bluetooth LEを使ってデータのやりとりを行います。
といっても、「[iOS] Bluetooth LEでデータのやりとり」でiOSのBluetooth LEの使い方を説明しましたので、AndroidのBluetooth LEの使い方の説明がメインになります。
Bluetooth LEの説明については「AndroidでiBeaconを発見する」を参照してください。
ペリフェラルとセントラルについて
Androidは現在、ペリフェラルになれません。Androidを使用する場合はセントラルとしてしか使用できません。
※ペリフェラル、セントラルの説明は「[iOS] Bluetooth LEでデータのやりとり」を参照してください。
ペリフェラルと接続する
iOSをペリフェラルにして、Androidをセントラルにしてデータのやり取りを行います。
・iOSをペリフェラルにする
「[iOS] Bluetooth LEでデータのやりとり」のiOSで接続する、ペリフェラルの実装を参考にしてください。
・Androidのセントラルの実装方法
1. BluetoothをActivityで使用できるようにする。
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
2. BluetoothManagerからBluetoothAdapterを取得します。
BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE); BluetoothAdapter mBluetoothAdapter = bluetoothManager.getAdapter();
3. BluetoothAdapterのstartLeScanを呼び出す。
mBluetoothAdapter.startLeScan(mLeScanCallback);
4. BluetoothAdapter.LeScanCallbackのonLeScanに結果が返ってくる。
private BluetoothAdapter.LeScanCallback mLeScanCallback = new BluetoothAdapter.LeScanCallback() { @Override public void onLeScan(final BluetoothDevice device, final int rssi, final byte[] scanRecord) { } }
ここまでは「AndroidでiBeaconを発見する」でも説明しています。
5. LeScanCallback#onLeScanで受け取ったBluetoothDevice#getAddressでアドレスを取得する。
public void onLeScan(final BluetoothDevice device, final int rssi, final byte[] scanRecord) { String address = device.getAddress(); }
6. アドレスからデバイスを検索して、接続する。
BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address); BluetoothGatt mBluetoothGatt = device.connectGatt(this, false, mGattCallback);
第一引数のthisはコンテキストです。第二引数はfalseは直接接続、trueは自動接続になるため、直接接続する際はfalseにします。第三引数はコールバックになります(7で説明します)。
7. BluetoothGattCallback#onConnectionStateChangeにstatusが成功が返ってくれれば接続が成功します。
private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() { @Override public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) { } @Override public void onServicesDiscovered(BluetoothGatt gatt, final int status) { } // 他にもOverrideできるメソッドがあるが省略 };
8. 接続完了後、ペリフェラルのサービス一覧がBluetoothGattCallback#onServicesDiscoveredに来ます。このサービス一覧を使用して、ペリフェラルとデータのやり取りができるようになります。
データのやりとり[write]
1. BluetoothGattCallback#onServicesDiscoveredで書きたいサービスを保存しておきます。
BluetoothGattService myService = gatt.getService(UUID.fromString("自分で定義したサービスのUUID")); BluetoothGattCharacteristic myChar = confirmService.getCharacteristic(UUID.fromString("自分で定義したキャラクリスティックのUUID"));
2. 送るデータを設定する。
myChar.setValue("送るデータ");
3. データをペリフェラルに送る。
mBluetoothGatt.writeCharacteristic(myChar);
データのやりとり[read]
1. BluetoothGattCallback#onServicesDiscoveredで読みたいサービスを保存しておきます。
BluetoothGattService myService = gatt.getService(UUID.fromString("自分で定義したサービスのUUID")); BluetoothGattCharacteristic myChar = confirmService.getCharacteristic(UUID.fromString("自分で定義したキャラクリスティックのUUID"));
2. データをペリフェラルから読み込み。
mBluetoothGatt.readCharacteristic(myChar);
3. ペリフェラルからデータが返答される。BluetoothGattCallback#onCharacteristicReadに通知される。
4. 送られてきたデータの取得をする。onCharacteristicReadの引数のBluetoothGattCharacteristicから読み取れる。
final byte[] data = characteristic.getValue()
データのやりとり[notification]
1. BluetoothGattCallback#onServicesDiscoveredで通知のサービスを保存しておきます。
BluetoothGattService myService = gatt.getService(UUID.fromString("自分で定義したサービスのUUID")); BluetoothGattCharacteristic myChar = confirmService.getCharacteristic(UUID.fromString("自分で定義したキャラクリスティックのUUID"));
2. 通知を設定します。
BluetoothGattDescriptor descriptor = characteristic.getDescriptor(UUID.fromString("00002902-0000-1000-8000-00805f9b34fb")); descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
3. ペリフェラルから通知がきた場合。BluetoothGattCallback#onCharacteristicChangedが呼ばれる。値は引数のBluetoothGattCharacteristicから読み取れる。
final byte[] data = characteristic.getValue()
AndroidのDeveloperページにBluetooth LEの実装方法がのっているので参考にしてください。
・参考ページ
http://developer.android.com/guide/topics/connectivity/bluetooth-le.html
これでiOSとAndroid間でBluetooth LEを使用してデータのやりとりができます。
ただし、Nexus 5で試したところ、notificationを複数設定しても最初に設定したものしか反映されなかったり、Androidか端末依存なのかわかりませんが、制限がありそうです。(iPhone 5S iOS7では複数のnotificationを設定できました。)