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