Android
Bluetooth Low Energy
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);
}