Android - Не удалось подключиться к устройству Bluetooth на Lollipop
У меня есть приложение, хорошо работающее на Android 4.3 и 4.4.
Приложение будет подключаться и взаимодействовать с пользовательским устройством Bluetooth.
После того, как я внезапно выслал Nexus 5 на Lollipop, я не могу подключиться к устройству вообще. Результат соединения всегда равен 133. Это журнал:
D/BluetoothGatt﹕ connect() - device: 00:07:80:04:1A:5A, auto: true
D/BluetoothGatt﹕ registerApp()
D/BluetoothGatt﹕ registerApp() - UUID=xxxxxx-xxxx-xxxxx-xxxx-xxxxxxxx
D/BluetoothGatt﹕ onClientRegistered() - status=0 clientIf=6
D/BluetoothGatt﹕ onClientConnectionState() - status=133 clientIf=6 device=00:07:80:04:1A:5A
Мой код:
public boolean connect(final String address) {
if (mBluetoothAdapter == null || address == null) {
return false;
}
Handler handler = new Handler(Looper.getMainLooper());
// Previously connected device. Try to reconnect.
if (mBluetoothDeviceAddress != null
&& address.equals(mBluetoothDeviceAddress)
&& mBluetoothGatt != null) {
handler.post(new Runnable() {
@Override
public void run() {
if (mBluetoothGatt.connect()) {
mConnectionState = STATE_CONNECTING;
}
}
});
if (mConnectionState == STATE_CONNECTING) {
return true;
} else {
return false;
}
}
final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
if (device == null) {
return false;
}
handler.post(new Runnable() {
@Override
public void run() {
mBluetoothGatt = device.connectGatt(BluetoothConnectService.this, true, mGattCallback);
}
});
mBluetoothDeviceAddress = address;
mConnectionState = STATE_CONNECTING;
return true;
}
Кто-нибудь есть об этом?
Ответы
Ответ 1
Итак, я понял, что проблема заключается в выборе транспорта в Lollipop.
Как вы можете видеть в здесь изменение в
BluetoothDevice.connectGatt(Context context, boolean autoConnect, BluetoothGattCallback callback)
Функция вызывает
BluetoothDevice.connectGatt(Context context, boolean autoConnect, BluetoothGattCallback callback, int transport)
с транспортом, установленным на TRANSPORT_AUTO.
В моем случае, потому что я всегда буду использовать TRANSPORT_LE (значение равно 2)
Я попытался вызвать второй метод из своего кода и установить транспорт для TRANSPORT_LE.
По непонятной причине я не могу назвать это напрямую, поэтому я использую рефлексию для его вызова.
До сих пор это отлично работает для меня.
if(TTTUtilities.isLollipopOrAbove()) {
// Little hack with reflect to use the connect gatt with defined transport in Lollipop
Method connectGattMethod = null;
try {
connectGattMethod = device.getClass().getMethod("connectGatt", Context.class, boolean.class, BluetoothGattCallback.class, int.class);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
try {
mBluetoothGatt = (BluetoothGatt) connectGattMethod.invoke(device, BluetoothConnectService.this, false, mGattCallback, TRANSPORT_LE);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
} else {
mBluetoothGatt = device.connectGatt(BluetoothConnectService.this, true, mGattCallback);
}
Если у кого-то из вас есть вопрос о моем ответе, не стесняйтесь спрашивать в комментарии.
Спасибо.
Ответ 2
Для Xamarin пользователей, имеющих такую же проблему, вот несколько другое решение. У меня была такая же проблема с Nexus 7 Android 6 с использованием кросс-платформенной SDK Xamarin. Исправлена проблема использования TRANSPORT_LE. Вместо использования Reflection для получения метода по его сигнатуре (не работает), можно использовать Reflection для повторения всех методов до тех пор, пока вы не найдете подходящее имя. См. Следующий код:
BluetoothDevice bd = (BluetoothDevice)device.NativeDevice;
Java.Lang.Reflect.Method[] methods = bd.Class.GetDeclaredMethods();
foreach (Java.Lang.Reflect.Method possibleConnectGattMethod in methods)
{
// Find matching method name connectGatt and then invoke it with TRANSPORT_LE
}
Ответ 3
Я не думаю, что вызов метода connectGatt, использующего отражение, является разумным. Поскольку частные функции могут быть изменены в любое время с обновлением, ваше приложение не работает.
И в любом случае TRANSPORT_AUTO должен попытаться подключиться к вашему периферийному устройству желаемым образом, если в вашем периферийном рекламном пакете установлены соответствующие флаги. Если ваше периферийное устройство не поддерживает режим TRANSPORT_BREDR, тогда есть стандартный флаг "BrEdrNotSupported", который вы должны установить в рекламных данных, чтобы центральные знали об этом.
Ответ 4
Какой тип BLE IC вы используете? Если это CC254x, это может быть связано с проблемами в их стеке программного обеспечения для периферийных устройств:
https://e2e.ti.com/support/wireless_connectivity/f/538/t/401240