Android
Bluetooth Low Energy
Recherche…
Introduction
Cette documentation se veut une amélioration par rapport à la documentation originale et se concentrera sur la dernière API Bluetooth LE introduite dans Android 5.0 (API 21). Les rôles centraux et périphériques seront couverts, ainsi que le démarrage des opérations de numérisation et de publicité.
Recherche de périphériques BLE
Les autorisations suivantes sont requises pour utiliser les API Bluetooth:
android.permission.BLUETOOTH android.permission.BLUETOOTH_ADMIN
Si vous ciblez des appareils avec Android 6.0 ( API niveau 23 ) ou supérieur et que vous souhaitez effectuer des opérations d'analyse / de publicité, vous aurez besoin d'une autorisation de localisation:
android.permission.ACCESS_FINE_LOCATION
ou
android.permission.ACCESS_COARSE_LOCATION
Remarque.- Les services de localisation avec Android 6.0 (API niveau 23) ou plus doivent également avoir les services de localisation activés.
Un objet BluetoothAdapter est requis pour démarrer les opérations d'analyse / de publicité:
BluetoothManager bluetoothManager = (BluetoothManager) context.getSystemService(Context.BLUETOOTH_SERVICE);
bluetoothAdapter = bluetoothManager.getAdapter();
La startScan (ScanCallback callback)
de la classe BluetoothLeScanner est la méthode la plus simple pour démarrer une opération d'analyse. Un objet ScanCallback
est requis pour recevoir les résultats:
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());
}
});
Connexion à un serveur GATT
Une fois que vous avez découvert un objet BluetoothDevice, vous pouvez vous y connecter en utilisant sa méthode connectGatt()
qui prend en paramètre un objet Context, un booléen indiquant s'il faut se connecter automatiquement à l'appareil BLE et une référence BluetoothGattCallback où les événements de connexion et les opérations client les résultats seront livrés:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
device.connectGatt(context, false, bluetoothGattCallback, BluetoothDevice.TRANSPORT_AUTO);
} else {
device.connectGatt(context, false, bluetoothGattCallback);
}
Remplacez onConnectionStateChange
dans BluetoothGattCallback pour recevoir une connexion des événements de déconnexion:
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.");
}
}
};
Écrire et lire à partir de caractéristiques
Une fois connecté à un serveur Gatt, vous allez interagir avec lui en écrivant et en lisant les caractéristiques du serveur. Pour ce faire, vous devez d’abord découvrir quels services sont disponibles sur ce serveur et quelles caractéristiques sont disponibles dans chaque service:
@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
}
}
}
}
Une opération d'écriture de base se déroule comme suit:
characteristic.setValue(newValue);
characteristic.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT);
gatt.writeCharacteristic(characteristic);
Lorsque le processus d'écriture est terminé, la méthode onCharacteristicWrite
de votre BluetoothGattCallback
sera appelée:
@Override
public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
super.onCharacteristicWrite(gatt, characteristic, status);
Log.d(TAG, "Characteristic " + characteristic.getUuid() + " written);
}
Une opération d'écriture de base se déroule comme suit:
gatt.readCharacteristic(characteristic);
Lorsque le processus d'écriture est terminé, la méthode onCharacteristicRead
de votre BluetoothGattCallback
sera appelée:
@Override
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
super.onCharacteristicRead(gatt, characteristic, status);
byte[] value = characteristic.getValue();
}
Abonnement aux notifications du serveur Gatt
Vous pouvez demander à être averti par le serveur Gatt lorsque la valeur d'une caractéristique a été modifiée:
gatt.setCharacteristicNotification(characteristic, true);
BluetoothGattDescriptor descriptor = characteristic.getDescriptor(
UUID.fromString("00002902-0000-1000-8000-00805f9b34fb");
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
mBluetoothGatt.writeDescriptor(descriptor);
Toutes les notifications du serveur seront reçues dans la méthode onCharacteristicChanged
de votre BluetoothGattCallback:
@Override
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
super.onCharacteristicChanged(gatt, characteristic);
byte[] newValue = characteristic.getValue();
}
Publicité d'un appareil BLE
Vous pouvez utiliser la publicité Bluetooth LE pour diffuser des paquets de données sur tous les appareils à proximité sans avoir à établir au préalable une connexion. Gardez à l'esprit qu'il existe une limite stricte de 31 octets de données publicitaires. La publicité de votre appareil est également la première étape pour permettre aux autres utilisateurs de se connecter à vous.
Comme tous les appareils ne prennent pas en charge la publicité Bluetooth LE, la première étape consiste à vérifier que votre appareil dispose de toutes les conditions requises pour le prendre en charge. Ensuite, vous pouvez initialiser un objet BluetoothLeAdvertiser
et avec cela, vous pouvez lancer des opérations publicitaires:
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);
}
Utiliser un serveur Gatt
Pour que votre appareil puisse agir en tant que périphérique, vous devez d'abord ouvrir un BluetoothGattServer
et le remplir avec au moins un BluetoothGattService
et un BluetoothGattCharacteristic
:
BluetoothGattServer server=bluetoothManager.openGattServer(context, bluetoothGattServerCallback);
BluetoothGattService service = new BluetoothGattService(SERVICE_UUID, BluetoothGattService.SERVICE_TYPE_PRIMARY);
Ceci est un exemple d'une caractéristique BluetoothGattCharacter avec des autorisations d'écriture, de lecture et de notification complètes. Selon vos besoins, vous souhaiterez peut-être affiner les autorisations que vous accordez à cette caractéristique:
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
est chargé de recevoir tous les événements liés à votre 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);
}
Chaque fois que vous recevez une demande d'écriture / lecture sur une caractéristique ou un descripteur, vous devez lui envoyer une réponse pour que la demande soit complétée avec succès:
@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);
}