Buscar..


Introducción

Esta documentación pretende ser una mejora con respecto a la documentación original y se centrará en la última API de Bluetooth LE introducida en Android 5.0 (API 21). Se cubrirán los roles tanto Central como Periférico, así como la forma de iniciar las operaciones de escaneo y publicidad.

Buscando dispositivos BLE

Se requieren los siguientes permisos para usar las API de Bluetooth:

android.permission.BLUETOOTH
android.permission.BLUETOOTH_ADMIN

Si está apuntando a dispositivos con Android 6.0 ( nivel de API 23 ) o superior y desea realizar operaciones de escaneo / publicidad, necesitará un permiso de ubicación:

android.permission.ACCESS_FINE_LOCATION

o

android.permission.ACCESS_COARSE_LOCATION

Nota.- Los dispositivos con Android 6.0 (nivel de API 23) o superior también deben tener habilitados los Servicios de ubicación.

Se requiere un objeto BluetoothAdapter para iniciar las operaciones de escaneo / publicidad:

BluetoothManager bluetoothManager = (BluetoothManager) context.getSystemService(Context.BLUETOOTH_SERVICE);
bluetoothAdapter = bluetoothManager.getAdapter();

El startScan (ScanCallback callback) de la clase BluetoothLeScanner es la forma más básica de iniciar una operación de escaneo. Se ScanCallback objeto ScanCallback para recibir resultados:

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

Conectando a un servidor GATT

Una vez que haya descubierto un objeto BluetoothDevice deseado, puede conectarse utilizando su método connectGatt() , que toma como parámetros un objeto Context, un booleano que indica si debe conectarse automáticamente al dispositivo BLE y una referencia BluetoothGattCallback donde los eventos de conexión y las operaciones del cliente Los resultados serán entregados:

 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        device.connectGatt(context, false, bluetoothGattCallback, BluetoothDevice.TRANSPORT_AUTO);
    } else {
        device.connectGatt(context, false, bluetoothGattCallback);
    }

Reemplace onConnectionStateChange en BluetoothGattCallback para recibir conexión y eventos de desconexión:

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

Escritura y lectura de características.

Una vez que estés conectado a un servidor Gatt, estarás interactuando escribiendo y leyendo las características del servidor. Para hacer esto, primero debe descubrir qué servicios están disponibles en este servidor y qué características están disponibles en cada servicio:

 @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         
                    }
                 }
              }
            }

Una operación básica de escritura es la siguiente:

characteristic.setValue(newValue);
characteristic.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT);
gatt.writeCharacteristic(characteristic);

Cuando el proceso de escritura haya finalizado, se onCharacteristicWrite método onCharacteristicWrite de su BluetoothGattCallback :

    @Override
    public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
        super.onCharacteristicWrite(gatt, characteristic, status);
        Log.d(TAG, "Characteristic " + characteristic.getUuid() + " written);
    }

Una operación básica de escritura es la siguiente:

gatt.readCharacteristic(characteristic);

Cuando el proceso de escritura haya finalizado, se onCharacteristicRead método onCharacteristicRead de su BluetoothGattCallback :

@Override
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
  super.onCharacteristicRead(gatt, characteristic, status);
  byte[] value = characteristic.getValue();
  }

Suscripción a notificaciones desde el servidor Gatt

Puede solicitar que se le notifique al Servidor Gatt cuando se haya cambiado el valor de una característica:

gatt.setCharacteristicNotification(characteristic, true);
BluetoothGattDescriptor descriptor = characteristic.getDescriptor(
    UUID.fromString("00002902-0000-1000-8000-00805f9b34fb");
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
mBluetoothGatt.writeDescriptor(descriptor);

Todas las notificaciones del servidor se recibirán en el método onCharacteristicChanged de su BluetoothGattCallback:

    @Override
    public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
        super.onCharacteristicChanged(gatt, characteristic);
        byte[] newValue = characteristic.getValue();
}

Publicidad de un dispositivo BLE

Puede usar Bluetooth LE Advertising para transmitir paquetes de datos a todos los dispositivos cercanos sin tener que establecer una conexión primero. Tenga en cuenta que hay un límite estricto de 31 bytes de datos de publicidad. La publicidad de su dispositivo también es el primer paso para permitir que otros usuarios se conecten con usted.

Dado que no todos los dispositivos son compatibles con Bluetooth LE Advertising, el primer paso es verificar que su dispositivo tenga todos los requisitos necesarios para admitirlo. Después, puede inicializar un objeto BluetoothLeAdvertiser y con él, puede iniciar operaciones de publicidad:

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

Usando un servidor Gatt

Para que su dispositivo actúe como un periférico, primero debe abrir un BluetoothGattServer servidor de BluetoothGattServer y rellenarlo con al menos un servicio de BluetoothGattService y una característica de caracteres de BluetoothGattCharacteristic :

BluetoothGattServer server=bluetoothManager.openGattServer(context, bluetoothGattServerCallback);

BluetoothGattService service = new BluetoothGattService(SERVICE_UUID, BluetoothGattService.SERVICE_TYPE_PRIMARY);

Este es un ejemplo de BluetoothGattCharacteristic con permisos completos de escritura, lectura y notificación. De acuerdo con sus necesidades, es posible que desee ajustar los permisos que otorga esta característica:

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

El BluetoothGattServerCallback es responsable de recibir todos los eventos relacionados con su 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);
                }

Siempre que reciba una solicitud de escritura / lectura de una característica o descriptor, debe enviar una respuesta para que la solicitud se complete con éxito:

@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
Licenciado bajo CC BY-SA 3.0
No afiliado a Stack Overflow