Android
Bluetooth低エネルギー
サーチ…
前書き
このドキュメントは、 元のドキュメントを拡張したものであり、Android 5.0(API 21)で導入された最新のBluetooth LE APIに焦点を当てています。中央と周辺の両方の役割と、スキャンと広告の操作を開始する方法について説明します。
BLEデバイスの検索
Bluetooth APIを使用するには、次の権限が必要です。
android.permission.BLUETOOTH android.permission.BLUETOOTH_ADMIN
Android 6.0( APIレベル23 )以上の端末をターゲティングしていて、スキャン/広告操作を実行する場合は、場所の権限が必要です。
android.permission.ACCESS_FINE_LOCATION
または
android.permission.ACCESS_COARSE_LOCATION
注:Android 6.0(APIレベル23)以上のデバイスでも、位置情報サービスを有効にする必要があります。
スキャン/広告操作を開始するには、BluetoothAdapterオブジェクトが必要です。
BluetoothManager bluetoothManager = (BluetoothManager) context.getSystemService(Context.BLUETOOTH_SERVICE);
bluetoothAdapter = bluetoothManager.getAdapter();
BluetoothLeScannerクラスのstartScan (ScanCallback callback)
メソッドは、スキャン操作を開始する最も基本的な方法です。結果を受け取るには、 ScanCallback
オブジェクトが必要です。
bluetoothAdapter.getBluetoothLeScanner().startScan(new ScanCallback() {
@Override
public void onScanResult(int callbackType, ScanResult result) {
super.onScanResult(callbackType, result);
Log.i(TAG, "Remote device name: " + result.getDevice().getName());
}
});
GATTサーバへの接続
目的のBluetoothDeviceオブジェクトを検出したら、そのオブジェクトにパラメータとしてconnectGatt()
メソッドを使用して接続できます。このメソッドは、BLEデバイスに自動的に接続するかどうかを示すブール値と接続イベントとクライアント操作が含まれるBluetoothGattCallback参照結果は配信されます:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
device.connectGatt(context, false, bluetoothGattCallback, BluetoothDevice.TRANSPORT_AUTO);
} else {
device.connectGatt(context, false, bluetoothGattCallback);
}
BluetoothGattCallbackのonConnectionStateChange
をオーバーライドして接続を切断します。
BluetoothGattCallback bluetoothGattCallback =
new BluetoothGattCallback() {
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status,
int newState) {
if (newState == BluetoothProfile.STATE_CONNECTED) {
Log.i(TAG, "Connected to GATT server.");
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
Log.i(TAG, "Disconnected from GATT server.");
}
}
};
特性への書き込みと読み取り
Gatt Serverに接続すると、サーバーの特性を書き込んだり読んだりすることで、Gatt Serverとやりとりすることになります。これを行うには、まずこのサーバー上で利用可能なサービスと各サービスで使用できる特性を発見する必要があります。
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status,
int newState) {
if (newState == BluetoothProfile.STATE_CONNECTED) {
Log.i(TAG, "Connected to GATT server.");
gatt.discoverServices();
}
. . .
@Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
List<BluetoothGattService> services = gatt.getServices();
for (BluetoothGattService service : services) {
List<BluetoothGattCharacteristic> characteristics = service.getCharacteristics();
for (BluetoothGattCharacteristic characteristic : characteristics) {
///Once you have a characteristic object, you can perform read/write
//operations with it
}
}
}
}
基本的な書き込み操作は次のようになります。
characteristic.setValue(newValue);
characteristic.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT);
gatt.writeCharacteristic(characteristic);
書き込み処理が終了すると、 BluetoothGattCallback
onCharacteristicWrite
メソッドが呼び出されます。
@Override
public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
super.onCharacteristicWrite(gatt, characteristic, status);
Log.d(TAG, "Characteristic " + characteristic.getUuid() + " written);
}
基本的な書き込み操作は次のようになります。
gatt.readCharacteristic(characteristic);
書き込み処理が終了すると、 BluetoothGattCallback
onCharacteristicRead
メソッドが呼び出されます。
@Override
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
super.onCharacteristicRead(gatt, characteristic, status);
byte[] value = characteristic.getValue();
}
ガットサーバーからの通知の購読
特性の値が変更されたときに、Gatt Serverに通知するようリクエストできます。
gatt.setCharacteristicNotification(characteristic, true);
BluetoothGattDescriptor descriptor = characteristic.getDescriptor(
UUID.fromString("00002902-0000-1000-8000-00805f9b34fb");
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
mBluetoothGatt.writeDescriptor(descriptor);
サーバーからのすべての通知は、BluetoothGattCallbackのonCharacteristicChanged
メソッドで受信されます。
@Override
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
super.onCharacteristicChanged(gatt, characteristic);
byte[] newValue = characteristic.getValue();
}
BLEデバイスの広告
Bluetooth LE Advertisingを使用すると、まず接続を確立せずに、近くのすべてのデバイスにデータパッケージをブロードキャストできます。 31バイトの広告データには厳しい制限があることに注意してください。あなたのデバイスを宣伝することは、他のユーザーがあなたに接続できるようにするための第一歩です。
すべてのデバイスがBluetooth LE Advertisingをサポートしているわけではないため、最初に、デバイスがサポートするために必要なすべての要件を満たしていることを確認する必要があります。その後、 BluetoothLeAdvertiser
オブジェクトを初期化することができ、広告操作を開始することができます:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && bluetoothAdapter.isMultipleAdvertisementSupported())
{
BluetoothLeAdvertiser advertiser = bluetoothAdapter.getBluetoothLeAdvertiser();
AdvertiseData.Builder dataBuilder = new AdvertiseData.Builder();
//Define a service UUID according to your needs
dataBuilder.addServiceUuid(SERVICE_UUID);
dataBuilder.setIncludeDeviceName(true);
AdvertiseSettings.Builder settingsBuilder = new AdvertiseSettings.Builder();
settingsBuilder.setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_LOW_POWER);
settingsBuilder.setTimeout(0);
//Use the connectable flag if you intend on opening a Gatt Server
//to allow remote connections to your device.
settingsBuilder.setConnectable(true);
AdvertiseCallback advertiseCallback=new AdvertiseCallback() {
@Override
public void onStartSuccess(AdvertiseSettings settingsInEffect) {
super.onStartSuccess(settingsInEffect);
Log.i(TAG, "onStartSuccess: ");
}
@Override
public void onStartFailure(int errorCode) {
super.onStartFailure(errorCode);
Log.e(TAG, "onStartFailure: "+errorCode );
}
};
advertising.startAdvertising(settingsBuilder.build(),dataBuilder.build(),advertiseCallback);
}
ガットサーバーの使用
デバイスをペリフェラルとして機能させるには、まずBluetoothGattServer
を開いて、少なくとも1つのBluetoothGattService
と1つのBluetoothGattCharacteristic
を設定する必要がありBluetoothGattCharacteristic
。
BluetoothGattServer server=bluetoothManager.openGattServer(context, bluetoothGattServerCallback);
BluetoothGattService service = new BluetoothGattService(SERVICE_UUID, BluetoothGattService.SERVICE_TYPE_PRIMARY);
これは、フル書き込み、読み取り、通知のパーミッションを持つBluetoothGattCharacteristicの例です。必要に応じて、この特性を付与する権限を細かく調整することができます。
BluetoothGattCharacteristic characteristic = new BluetoothGattCharacteristic(CHARACTERISTIC_UUID,
BluetoothGattCharacteristic.PROPERTY_READ | BluetoothGattCharacteristic.PROPERTY_WRITE |
BluetoothGattCharacteristic.PROPERTY_NOTIFY,
BluetoothGattCharacteristic.PERMISSION_READ | BluetoothGattCharacteristic.PERMISSION_WRITE);
characteristic.addDescriptor(new BluetoothGattDescriptor(UUID.fromString("00002902-0000-1000-8000-00805f9b34fb"), BluetoothGattCharacteristic.PERMISSION_WRITE));
service.addCharacteristic(characteristic);
server.addService(service);
BluetoothGattServerCallback
は、 BluetoothGattServer
関連するすべてのイベントを受信します。
BluetoothGattServerCallback bluetoothGattServerCallback= new BluetoothGattServerCallback() {
@Override
public void onConnectionStateChange(BluetoothDevice device, int status, int newState) {
super.onConnectionStateChange(device, status, newState);
}
@Override
public void onCharacteristicReadRequest(BluetoothDevice device, int requestId, int offset, BluetoothGattCharacteristic characteristic) {
super.onCharacteristicReadRequest(device, requestId, offset, characteristic);
}
@Override
public void onCharacteristicWriteRequest(BluetoothDevice device, int requestId, BluetoothGattCharacteristic characteristic, boolean preparedWrite, boolean responseNeeded, int offset, byte[] value) {
super.onCharacteristicWriteRequest(device, requestId, characteristic, preparedWrite, responseNeeded, offset, value);
}
@Override
public void onDescriptorReadRequest(BluetoothDevice device, int requestId, int offset, BluetoothGattDescriptor descriptor) {
super.onDescriptorReadRequest(device, requestId, offset, descriptor);
}
@Override
public void onDescriptorWriteRequest(BluetoothDevice device, int requestId, BluetoothGattDescriptor descriptor, boolean preparedWrite, boolean responseNeeded, int offset, byte[] value) {
super.onDescriptorWriteRequest(device, requestId, descriptor, preparedWrite, responseNeeded, offset, value);
}
特性または記述子への書込み/読込みの要求を受け取ると、その要求が成功裏に完了するために応答を送信する必要があります。
@Override
public void onCharacteristicReadRequest(BluetoothDevice device, int requestId, int offset, BluetoothGattCharacteristic characteristic) {
super.onCharacteristicReadRequest(device, requestId, offset, characteristic);
server.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, YOUR_RESPONSE);
}