Android 4.3 Bluetooth Низкая энергия нестабильная

В настоящее время я разрабатываю приложение, которое будет использовать Bluetooth Low Energy (тестирование на Nexus 4). После начала работы с официальными API-интерфейсами BLE в Android 4.3 я заметил, что после подключения устройства в первый раз я редко могу успешно подключиться к этому устройству или другому устройству снова.

Следуя руководству здесь, я могу успешно подключиться к устройству, сканировать службы и характеристики, а также читать/писать/получать уведомления без каких-либо проблем. Однако после отсоединения и повторного подключения я часто не могу ни сканировать службы/характеристики, либо не смог завершить чтение/запись. Я не могу найти ничего в журналах, чтобы указать, почему это происходит.

Как только это произойдет, я должен удалить приложение, отключить Bluetooth и перезагрузить телефон, прежде чем он начнет работать снова.

Всякий раз, когда устройство отключено, я вызываю вызов close() в объекте BluetoothGatt и устанавливаю его в значение null. Любые идеи?


EDIT:
Лог-дампы: для этих журналов я укоренил свой телефон и увеличил уровни трассировки связанных элементов в файле /etc/bluetooth/bt _stack.conf

Успешное подключение - Первая попытка после перезагрузки телефона и установки приложения. Я могу подключиться, обнаружить все сервисы/характеристики и читать/писать.

Failed Attempt 1 - Это следующая попытка после отсоединения от успешного соединения выше. Кажется, мне удалось обнаружить характеристики, но первая попытка чтения вернула нулевое значение и вскоре была отключена.

Failed Attempt 2 - пример, когда я даже не могу обнаружить службы/характеристики.


ИЗМЕНИТЬ 2:
Устройство, к которому я пытаюсь подключиться, основано на чипе TI CC2541. Я получил TI SensorTag (также основанный на CC2541), чтобы поиграть и обнаружил, что TI выпустил приложение для Android для SensorTag вчера. Тем не менее, это приложение имеет ту же проблему. Я тестировал это на двух других Nexus 4 с тем же результатом: соединение с SensorTag успешно выполняется первый или второй раз, но (в соответствии с журналами) не удается в дальнейшем обнаруживать службы, вызывая всевозможные сбои. Я начинаю задаваться вопросом, не проблема с этим конкретным чипом?

Ответ 1

Важные советы по реализации

(Возможно, некоторые из этих подсказок больше не нужны из-за обновлений ОС Android.)

  1. Некоторым устройствам, таким как Nexus 4 с Android 4.3, требуется 45+ секунд для подключения с использованием существующего экземпляра gatt. Обходной путь: Всегда закрывайте экземпляры gatt при разъединении и создавайте новый экземпляр gatt при каждом подключении.
  2. Не забудьте позвонить на android.bluetooth.BluetoothGatt#close()
  3. Начать новый поток внутри onLeScan(..) а затем подключиться. Причина: BluetoothDevice#connectGatt(Context context, boolean autoConnect, BluetoothGattCallback callback) всегда завершается ошибкой, если LeScanCallback() {...}.onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) внутри LeScanCallback() {...}.onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) в том же потоке в Samsung Galaxy S3 с Android 4.3 (по крайней мере, для сборки JSS15J.I9300XXUGMK6)
  4. Большинство устройств фильтруют рекламу
  5. Лучше не использовать android.bluetooth.BluetoothAdapter#startLeScan(UUID[] serviceUuids, LeScanCallback callback) с параметром фильтрации определенных UUID службы, потому что это полностью не работает в Samsung Galaxy S3 с Android 4.3 и не работает для 128-битных UUID в целом,
  6. Гатт всегда может обрабатывать одну команду за раз. Если несколько команд вызываются по очереди, первая отменяется из-за синхронного характера реализации gatt.
  7. Я часто вижу даже на современных устройствах с Android 5, что Wi-Fi мешает с Bluetooth и наоборот. В крайнем случае, отключите Wi-Fi, чтобы стабилизировать Bluetooth.

Учебник для начинающих

Хорошим отправным пунктом для новичков может стать видеоурок: "Разработка приложений Bluetooth для Android" http://youtu.be/x1y4tEHDwk0

Описанная ниже проблема и способ ее устранения, вероятно, теперь устраняются обновлениями ОС

Обойти: я мог бы "стабилизировать" мое приложение, делая это...

  1. Я предоставляю пользователю настройку "Перезагрузить Bluetooth". Если этот параметр включен, я перезагружаю Bluetooth в некоторых точках, которые указывают, что начало стека BLE становится нестабильным. Например, если startScan возвращает false. Хорошим моментом также может быть, если serviceDiscovery не работает. Я просто выключаю и включаю Bluetooth.
  2. Я предоставляю другую настройку "Отключить WiFi". Если этот параметр включен, мое приложение отключает Wi-Fi во время его работы (и затем снова включает его)

Эта работа основана на следующем опыте...

  • Перезапуск Bluetooth помогает исправить проблемы с BLE в большинстве случаев
  • Если вы отключите Wi-Fi, стек BLE станет намного стабильнее. Тем не менее, он также работает нормально на большинстве устройств с включенным Wi-Fi.
  • Если вы отключите Wi-Fi, перезапуск Bluetooth полностью восстановит стек BLE без необходимости перезагрузки устройства в большинстве случаев.

Ответ 2

Отключение WIFI:

Я также могу подтвердить, что поворот WIFI OFF делает Bluetooth 4.0 более стабильным, особенно в Google Nexus (у меня есть Nexus 7).

Проблема

заключается в том, что для приложения, которое я разрабатываю , требуется как WIFI, так и непрерывное сканирование Bluetooth LE. Поэтому поворот WIFI OFF для меня не был вариантом.

Кроме того, я понял, что непрерывное сканирование Bluetooth LE может фактически убить WIFI-соединение и сделать адаптер WIFI неспособным повторно подключиться к любая сеть WIFI до тех пор, пока проверка BLE не будет включена. (Я не уверен в мобильных сетях и мобильном Интернете). Это определенно произошло на следующих устройствах:

  • Nexus 7
  • Motorola Moto G

Однако сканирование BLE с WIFI показалось довольно стабильным:

  • Samsung S4
  • HTC One

Мое обходное решение

I сканировать BLE для короткого периода времени 3-4 секунды, затем я выключить сканирование в течение 3-4 секунд. Затем снова включите.

  • Очевидно, что я всегда выключаю BLE-сканирование OFF, когда я подключаюсь к устройству BLE.
  • Когда я отсоединяюсь от устройства, я перезапускаю BLE (выключите адаптер, а затем ВКЛ) до reset стека перед повторным запуском сканирования.
  • Я также reset BLE, когда обнаруживаются ошибки services или characteristics.
  • Когда я получаю рекламные данные с устройства, к которому приложение должно подключиться (скажем, 500 раз, не имея возможности подключиться - это примерно 5-10 секунд рекламы) я reset BLE снова.

Ответ 3

Убедитесь, что ваш Nexus сопряжен с устройством. Я не могу проверить, правильно ли работает связь, но вы можете подключаться несколько раз без перезагрузки. Кажется, что первое соединение не требует сопряжения, но все последующие попытки делают.

Я обновляю этот ответ через пару дней, когда я тестирую обнаружение службы и gatt-запросы на чтение и запись без перезагрузки.

EDIT: Оказывается, я тестировал версию прошивки разработки (наш датчик), которая вызывала проблемы, если не была сопряжена. Наша новейшая производственная прошивка прекрасно работает на 2540-х и 2541-х годах.

EDIT: Я заметил, что на Nexus 7 2013 соединения более стабильны при отключении Wi-Fi. Я хотел бы знать, помогает ли это кому-либо еще.

EDIT: Кажется, у меня было это с обратной связью. Все работает нормально, когда не сопряжено. После спаривания я испытываю те же симптомы, что и ОП. Пока этого не известно, если это связано с нашей прошивкой или Android BLE API. Будьте осторожны, если вы проверите это, потому что после спаривания вы не сможете устранить проблему из-за ошибки, описанной в 3b этой post.

Ответ 4

В некоторых моделях есть дефект: https://code.google.com/p/android/issues/detail?id=180440

С другой стороны, в моем случае проблема заключалась в том, что мое соединение не было должным образом закрыто в методе onDestroy. После правильного закрытия проблема для меня не существует, не важно, что Wi-Fi включен или выключен.

btGatt.disconnect();
btGatt.close();

Ответ 5

Я столкнулся с аналогичной проблемой. Мое исправление было

if (Build.VERSION.SDK_INT >= 23) {
  mBluetoothGatt = device.connectGatt(this, false, mGattCallback, BluetoothDevice.TRANSPORT_LE);
} else {
  mBluetoothGatt = device.connectGatt(this, false, mGattCallback);
}

& звонить закрыть после отключения.