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


Modified text is an extract of the original Stack Overflow Documentation
Sous licence CC BY-SA 3.0
Non affilié à Stack Overflow