Поиск…


Вступление

Эта документация предназначена для усовершенствования исходной документации, и она сосредоточится на новейшем интерфейсе Bluetooth LE, представленном в Android 5.0 (API 21). Будут рассмотрены как центральные, так и периферийные роли, а также как начать сканирование и рекламные операции.

Поиск устройств BLE

Для использования API-интерфейсов Bluetooth необходимы следующие разрешения:

android.permission.BLUETOOTH
android.permission.BLUETOOTH_ADMIN

Если вы настроили таргетинг на устройства с Android 6.0 ( API Level 23 ) или выше и хотите выполнять операции сканирования / рекламы, вам потребуется разрешение на размещение:

android.permission.ACCESS_FINE_LOCATION

или же

android.permission.ACCESS_COARSE_LOCATION

Примечание. Устройства с Android 6.0 (API Level 23) или выше также должны иметь службы определения местоположения.

Для запуска сканирования / рекламных операций требуется объект BluetoothAdapter:

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

Метод startScan (ScanCallback callback) класса BluetoothLeScanner является самым основным способом запуска операции сканирования. Для получения результатов требуется объект 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() который принимает в качестве параметров объект Context, логическое значение, указывающее, следует ли автоматически подключаться к устройству 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);
    }

Переопределить onConnectionStateChange в BluetoothGattCallback для получения соединения с событиями разъединения:

    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, вы будете взаимодействовать с ним, написав и прочитав характеристики сервера. Для этого сначала вам нужно выяснить, какие услуги доступны на этом сервере и какие характеристики доступны для каждой службы:

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

Когда процесс записи завершится, будет onCharacteristicWrite метод onCharacteristicWrite вашего BluetoothGattCallback :

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

Когда процесс записи завершится, будет onCharacteristicRead метод onCharacteristicRead вашего BluetoothGattCallback :

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

Подписка на уведомления с сервера Gatt

Вы можете запросить уведомление у сервера Gatt при изменении значения признака:

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

Все уведомления с сервера будут получены в методе onCharacteristicChanged вашего BluetoothGattCallback:

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

Использование сервера Gatt

Чтобы ваше устройство выступало в качестве периферии, сначала вам нужно открыть BluetoothGattServer и заполнить его, по крайней мере, одним BluetoothGattService и одним 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);
}


Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow