Android 4.3 Bluetooth энергосберегающий нестабильный
В настоящее время я занимаюсь разработкой приложения, которое будет использовать Bluetooth Low Energy (тестирование на Nexus 4). Начав работу с официальными API BLE в Android 4.3, я заметил, что после первого подключения устройства я редко могу успешно подключиться к этому устройству или любому другому устройству или связаться с ним.
Следуя приведенному здесь руководству, я могу без проблем подключаться к устройству, сканировать услуги и характеристики, а также читать / писать / получать уведомления. Однако после отключения и повторного подключения я часто не могу ни сканировать услуги / характеристики, ни выполнить чтение / запись. Я не могу найти ничего в журналах, чтобы указать, почему это происходит.
Как только это произойдет, я должен удалить приложение, отключить Bluetooth и перезагрузить телефон, прежде чем он снова начнет работать.
Всякий раз, когда устройство отключается, я вызываю функцию close() для объекта BluetoothGatt и устанавливаю для него значение null. Есть идеи?
РЕДАКТИРОВАТЬ:
Дампы журналов: для этих журналов я рутировал свой телефон и поднял уровни трассировки связанных элементов в /etc/bluetooth/bt_stack.conf
Успешное подключение - Первая попытка после перезагрузки телефона и установки приложения. Я могу подключиться, обнаружить все услуги / характеристики и читать / писать.
Неудачная попытка 1 - это следующая попытка после отключения от успешного подключения, описанного выше. Кажется, мне удалось обнаружить характеристики, но первая попытка чтения вернула нулевое значение и вскоре после этого отключилась.
Неудачная попытка 2 - пример, когда я даже не могу обнаружить услуги / характеристики.
РЕДАКТИРОВАТЬ 2:
Устройство, к которому я пытаюсь подключиться, основано на микросхеме TI CC2541. Я получил TI SensorTag (также основанный на CC2541), чтобы поиграть с ним, и обнаружил, что TI выпустила приложение для Android для SensorTag вчера. Тем не менее, это приложение имеет ту же проблему. Я проверил это на двух других Nexus 4 с тем же результатом: подключение к SensorTag было успешным в первый или второй раз, но (согласно журналам) не удается обнаружить службы после этого, вызывая всевозможные сбои. Я начинаю удивляться, если это проблема с этим конкретным чипом?
4 ответа
Важные советы по реализации
(Возможно, некоторые из этих подсказок больше не нужны из-за обновлений ОС Android.)
- Некоторым устройствам, таким как Nexus 4 с Android 4.3, требуется более 45 секунд для подключения с использованием существующего экземпляра gatt. Обходной путь: Всегда закрывайте экземпляры gatt при отключении и создавайте новый экземпляр gatt при каждом подключении.
- Не забудьте позвонить
android.bluetooth.BluetoothGatt#close()
- Начать новую тему внутри
onLeScan(..)
а затем подключиться. Причина:BluetoothDevice#connectGatt(Context context, boolean autoConnect, BluetoothGattCallback callback)
всегда терпит неудачу, если вызывается изнутриLeScanCallback() {...}.onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord)
в той же теме на Samsung Galaxy S3 с Android 4.3 (хотя бы для сборки JSS15J.I9300XXUGMK6) - Большинство устройств фильтруют рекламу
- Лучше не использовать
android.bluetooth.BluetoothAdapter#startLeScan(UUID[] serviceUuids, LeScanCallback callback)
с параметром фильтрации для определенных UUID службы, потому что он полностью нарушен в Samsung Galaxy S3 с Android 4.3 и не работает для 128-битных UUID в целом. - Гатт всегда может обрабатывать одну команду за раз. Если несколько команд вызываются по порядку, одна из них отменяется из-за синхронного характера реализации gatt.
- Я часто вижу даже на современных устройствах с Android 5, что Wi-Fi мешает с Bluetooth и наоборот. В крайнем случае, отключите Wi-Fi, чтобы стабилизировать Bluetooth.
Учебник для начинающих
Хорошим отправным пунктом для новичков может стать видеоурок: "Разработка приложений Bluetooth для Android" http://youtu.be/x1y4tEHDwk0
Описанная ниже проблема и способ ее устранения, вероятно, теперь исправлены обновлениями ОС
Обойти: я мог бы "стабилизировать" мое приложение, делая это...
- Я предоставляю пользователю настройку "Перезагрузить Bluetooth". Если этот параметр включен, я перезагружаю Bluetooth в некоторых точках, которые указывают, что начало стека BLE становится нестабильным. Например, если startScan возвращает false. Хорошим моментом также может быть, если serviceDiscovery не работает. Я просто выключаю и включаю Bluetooth.
- Я предоставляю другую настройку "Отключить WiFi". Если этот параметр включен, мое приложение отключает Wi-Fi во время его работы (и затем снова включает его)
Эта работа основана на следующем опыте...
- Перезапуск Bluetooth помогает исправить проблемы с BLE в большинстве случаев
- Если вы отключите Wi-Fi, стек BLE станет намного стабильнее. Тем не менее, он также отлично работает на большинстве устройств с включенным Wi-Fi.
- Если вы отключите Wi-Fi, перезапуск Bluetooth полностью восстановит стек BLE без необходимости перезагрузки устройства в большинстве случаев.
ВЫКЛЮЧЕНИЕ WIFI:
Я также могу подтвердить, что отключение WIFI делает Bluetooth 4.0 более стабильным, особенно в Google Nexus (у меня Nexus 7).
Эта проблема
в том, что разрабатываемое мной приложение требует как WIFI, так и непрерывного сканирования Bluetooth LE. Так что отключение WIFI не было для меня вариантом.
Более того, я понял, что непрерывное сканирование Bluetooth LE может фактически разорвать соединение WIFI и сделать адаптер WIFI неспособным повторно подключиться к любой сети WIFI, пока сканирование BLE не будет включено. (Я не уверен насчет мобильных сетей и мобильного интернета).
Это определенно произошло на следующих устройствах:
- Нексус 7
- Motorola Moto G
Однако BLE-сканирование с включенным WIFI показалось довольно стабильным:
- Samsung S4
- HTC One
Мой обходной путь
Я сканирую BLE в течение короткого промежутка времени 3-4 секунды, затем выключаю сканирование на 3-4 секунды. Затем снова.
- Очевидно, я всегда выключаю сканирование BLE при подключении к устройству BLE.
- Когда я отсоединяюсь от устройства, я перезагружаю BLE (выключите, а затем включите адаптер), чтобы сбросить стек перед повторным запуском сканирования.
- Я также сбрасываю BLE при обнаружении
services
или жеcharacteristics
выходит из строя. - Когда я получаю рекламные данные с устройства, к которому должно подключиться приложение (скажем, 500 раз без возможности подключения - это около 5-10 секунд рекламы), я снова сбрасываю BLE.
Убедитесь, что ваш Nexus подключен к устройству. Я не могу проверить, правильно ли работает связь, но вы сможете подключиться более одного раза без перезагрузки. Кажется, что первое соединение не требует сопряжения, но все последующие попытки делают.
Я обновлю этот ответ через пару дней, когда протестирую обнаружение службы и получу запросы на чтение и запись без перезагрузки.
РЕДАКТИРОВАТЬ: Оказывается, я тестировал версию встроенного программного обеспечения (наш датчик), который вызывал проблемы, если не было сопряжено. Наша последняя сборка серийной прошивки прекрасно работает на 2540-х и 2541-х годах.
РЕДАКТИРОВАТЬ: я заметил, что на Nexus 7 2013, соединения более стабильны, когда WiFi выключен. Я хотел бы знать, помогает ли это кому-нибудь еще.
РЕДАКТИРОВАТЬ: Я, кажется, было это задним числом с сопряжением. Все отлично работает, когда не в паре. После сопряжения я испытываю те же симптомы, что и ОП. Пока неизвестно, связано ли это с нашей прошивкой или Android BLE API. Будьте внимательны при тестировании этого, потому что после сопряжения вы, возможно, не сможете разорвать связь из-за ошибки, описанной в 3b этого поста.
В некоторых моделях есть дефект: https://code.google.com/p/android/issues/detail?id=180440
С другой стороны, в моем случае проблема заключалась в том, что мое соединение не было правильно закрыто в методе onDestroy. После корректного закрытия проблема для меня не существует, не важно, включен или выключен wifi.
btGatt.disconnect();
btGatt.close();
Я столкнулся с аналогичной проблемой. Мое исправление было
if (Build.VERSION.SDK_INT >= 23) {
mBluetoothGatt = device.connectGatt(this, false, mGattCallback, BluetoothDevice.TRANSPORT_LE);
} else {
mBluetoothGatt = device.connectGatt(this, false, mGattCallback);
}
& звонить закрыть после отключения.