AndroidとIOSでBluetooth通信するためには、BluetoothLeを使う必要があります。
ここでは、Bluetoothのサービスを使う側であるCentralと呼ばれる側の実装方法を見ていきます。
Leを使うためには、LOLLIPOP API以上である必要があります。
なので、Versionで処理を分ける必要があります。
ここでは、@TargetAPIを使ってファイルを分けます。
1 2 |
@TargetApi(Build.VERSION_CODES.LOLLIPOP) public class CentralLeBluetoothActivity extends FragmentActivity implements IBleActivity{ |
Bluetoothを使うために以下をメンバー変数として定義する
1 2 3 4 5 6 |
private BluetoothManager bleManager; private BluetoothAdapter bleAdapter; private boolean isBleEnabled = false; private BluetoothLeScanner bleScanner; private BluetoothGatt bleGatt; private BluetoothGattCharacteristic bleCharacteristic; |
初期化する
1 2 3 |
// Bluetoothの使用準備. bleManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE); bleAdapter = bleManager.getAdapter(); |
Peripheral端末の検索を開始する
端末のBluetoothが無効になっている場合、BluetoothAdapterクラスが有効になりませんので、
チェックをしないといけません。
1 2 3 4 |
if ((bleAdapter != null) || (bleAdapter.isEnabled())) { // BLEが使用可能ならスキャン開始. this.scanNewDevice(); } |
1 2 3 4 5 |
private void scanNewDevice(){ bleScanner = bleAdapter.getBluetoothLeScanner(); // デバイスの検出. bleScanner.startScan(scanCallback); } |
startScan関数にコールバックを渡しています。
このコールバックで状態の制御をしています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
private ScanCallback scanCallback = new ScanCallback() { @Override public void onScanResult(int callbackType, ScanResult result) { Log.d(TAG,"call onScanResult"); super.onScanResult(callbackType, result); // スキャン中に見つかったデバイスに接続を試みる.第三引数には接続後に呼ばれるBluetoothGattCallbackを指定する. result.getDevice().connectGatt(getApplicationContext(), false, gattCallback); } @Override public void onScanFailed(int intErrorCode) { Log.d(TAG,"call onScanFailed"); super.onScanFailed(intErrorCode); } }; |
検索が終わると
onScanResultが呼ばれます。そこで見つかったDeviceに対し接続を試みる関数が、
connectGat()関数で、ここにも接続の状態が返却されるcallbackを指定します。
また、第二引数には接続が切れた際に再度接続を試みるかどうかのフラグを設定することができます。
connectGat関数
connectGatt
BluetoothGatt connectGatt (Context context,
boolean autoConnect,
BluetoothGattCallback callback)
Connect to GATT Server hosted by this device. Caller acts as GATT client. The callback is used to deliver results to Caller, such as connection status as well as any further GATT client operations. The method returns a BluetoothGatt instance. You can use BluetoothGatt to conduct GATT client operations.
Parameters | |
---|---|
context |
Context |
autoConnect |
boolean : Whether to directly connect to the remote device (false) or to automatically connect as soon as the remote device becomes available (true). |
callback |
BluetoothGattCallback : GATT callback handler that will receive asynchronous callbacks. |
Returns | |
---|---|
BluetoothGatt |
Throws | |
---|---|
IllegalArgumentException |
if callback is null |
BluetoothGattCallback
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
private final BluetoothGattCallback gattCallback = new BluetoothGattCallback(){ @Override public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState){ // 接続状況が変化したら実行. if (newState == BluetoothProfile.STATE_CONNECTED) { Log.d(TAG,"call onConnectionStateChange STATE_CONNECTED"); // 接続に成功したらサービスを検索する. gatt.discoverServices(); } else if (newState == BluetoothProfile.STATE_DISCONNECTED) { Log.d(TAG,"call onConnectionStateChange STATE_DISCONNECTED"); // 接続が切れたらGATTを空にする. if (bleGatt != null){ bleGatt.close(); bleGatt = null; } isBleEnabled = false; } } @Override public void onServicesDiscovered(BluetoothGatt gatt, int status){ Log.d(TAG,"service discover state = " + status); // Serviceが見つかったら実行. if (status == BluetoothGatt.GATT_SUCCESS) { // UUIDが同じかどうかを確認する. BluetoothGattService bleService = gatt.getService(UUID.fromString(getString(R.string.uuid_service))); if (bleService != null){ // 指定したUUIDを持つCharacteristicを確認する. bleCharacteristic = bleService.getCharacteristic(UUID.fromString(getString(R.string.uuid_characteristic))); if (bleCharacteristic != null) { // Service, CharacteristicのUUIDが同じならBluetoothGattを更新する. bleGatt = gatt; // キャラクタリスティックが見つかったら、Notificationをリクエスト. bleGatt.setCharacteristicNotification(bleCharacteristic, true); // Characteristic の Notificationを有効化する. BluetoothGattDescriptor bleDescriptor = bleCharacteristic.getDescriptor( UUID.fromString(getString(R.string.uuid_characteristic_config))); bleDescriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE); bleGatt.writeDescriptor(bleDescriptor); // 接続が完了したらデータ送信を開始する. isBleEnabled = true; // scan 終了 Log.d(TAG,"call stop scan"); bleScanner.stopScan(scanCallback); } } } } @Override public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic){ Log.d(TAG,"call onCharacteristicChanged"); // キャラクタリスティックのUUIDをチェック(getUuidの結果が全て小文字で帰ってくるのでUpperCaseに変換) if (getString(R.string.uuid_characteristic).equals(characteristic.getUuid().toString().toUpperCase())){ runOnUiThread( () -> { // Peripheral側で更新された値をセットする. receivedValueView.setText(characteristic.getStringValue(0)); }); } } }; |
対象のサービスを探す
Bluetoothのサービスが見つかった時に呼ばれるのが、onServiceDiscovered関数です。
その関数内で、接続したい対象のサービスを探すために、各々のUUIDを指定する必要があります。
UUIDはそのサービスが固有にもつIDのことです。
サービスを発信する側つまりPeripheral端末側で、このUUID設定し、
各々のUUIDが一致した場合のみ接続を試みればいいわけです。
Peripheral端末にデータを送信する
では、Peripheral端末側にデータを送信します。
Button要素をタップした際にデータを送信するようにしました。
1 2 3 4 5 6 7 |
sendButton.setOnClickListener((View v) ->{ if(isBleEnabled){ Log.d(TAG,"send data"); bleCharacteristic.setValue(((EditText) findViewById(R.id.input_area)).getText().toString()); bleGatt.writeCharacteristic(bleCharacteristic); } }); |