Подтвердить что ты не робот

Обратный вызов GATT не регистрируется

Я пытаюсь написать приложение для отправки сообщений по Bluetooth Low Energy, которое затем будет передано UART в моей периферии. Я выполнил шаги здесь, и приложение сканирует и находит устройство успешно. Однако соединение с использованием метода BluetoothGatt = BluetoothDevice.connectGatt(контекст, автосоединение, обратный вызов) завершается неудачно, с логарифмом, в котором говорится: "Не удалось зарегистрировать обратный вызов".

Вызов:

//device scan callback
private BluetoothAdapter.LeScanCallback btScanCallback = new BluetoothAdapter.LeScanCallback() 
{
    @Override
    public void onLeScan(final BluetoothDevice device, final int rssi, final byte[] scanRecord)
    {       
        some stuff
        currBtGatt = device.connectGatt(parentActivity, false, btGattCallback);
    }
};

И обратный вызов Gatt:

//GATT callback
private BluetoothGattCallback btGattCallback = new BluetoothGattCallback()
{       
    @Override
    public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState)
    {
        // if connected successfully
        if(newState == BluetoothProfile.STATE_CONNECTED)
        {
            //discover services
            updateStatus("Connected");
            gatt.discoverServices();
        }
        else if(newState == BluetoothProfile.STATE_DISCONNECTED)
        {
            updateStatus("Disconnected");
        }
    }

    @Override
    public void onServicesDiscovered(BluetoothGatt gatt, int status)
    {
        if(status == BluetoothGatt.GATT_SUCCESS)
        {
            //pick out the (app side) transmit channel
            currBtService = gatt.getService(uartUuids[0]);
            currBtCharacteristic = currBtService.getCharacteristic(uartUuids[1]);
        }
        else 
        {
            updateStatus("Service discovery failed");
        }
    }
};

Logcat говорит:

11-19 10:40:39.363: D/BluetoothAdapter(11717): stopLeScan()
11-19 10:40:39.373: D/BluetoothGatt(11717): connect() - device: DC:6D:75:0C:0F:F9, auto: false
11-19 10:40:39.373: D/BluetoothGatt(11717): registerApp()
11-19 10:40:39.373: D/BluetoothGatt(11717): registerApp() - UUID=3ba20989-5026-4715-add3-a5e31684009a
11-19 10:40:39.373: I/BluetoothGatt(11717): Client registered, waiting for callback
11-19 10:40:49.373: E/BluetoothGatt(11717): Failed to register callback
11-19 10:40:49.533: D/BluetoothGatt(11717): onClientRegistered() - status=0 clientIf=5
11-19 10:40:49.533: E/BluetoothGatt(11717): Bad connection state: 0
11-19 10:40:49.593: D/BluetoothGatt(11717): onClientConnectionState() - status=0 clientIf=5 device=DC:6D:75:0C:0F:F9
11-19 10:40:49.593: W/BluetoothGatt(11717): Unhandled exception: java.lang.NullPointerException

Интересно, что мое периферийное устройство переходит в "подключенное" состояние (у меня есть светодиоды индикации), и я могу подключиться к нему с того же телефона с помощью демонстрационного приложения или с помощью ключа ПК BLE. Любые идеи оценили.

[EDIT] метод connectGatt возвращает значение null, которое, как мне кажется, ожидается.

[EDIT] При проверке исходного кода API 18 появляется сообщение "Не удалось зарегистрировать обратный вызов", потому что метод registerApp() возвращает false, потому что метод registerClient() IBluetoothGatt "mService" выдает удаленный исключение, вероятно, на строке:

enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");

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

4b9b3361

Ответ 1

Я, наконец, решил эту проблему. Устройство, которое я использую, - это Samsung Galaxy S4 и актуальная проблема (спасибо, что Wibble для руководства в вашем ответе, но вы немного в своем заключении) представляет собой проблему с потоками.

В ответе Wibble он заявил, что добавление кнопки для подключения исправляет его проблему. Я начал задаваться вопросом, почему это имеет значение, и я также могу подключиться и отключиться в течение всего сеанса без кнопки GUI, используя потоки рабочего потока. Как только я закрою приложение, перезагрузите его и попытайтесь подключиться, я начинаю получать сообщение об ошибке "Ошибка регистрации обратного вызова". и ничего не работает. Я почти вытащил волосы из-за этого:)

См. мой пост в форумах Samsung для более подробной информации о моих точных проблемах.

Решение: Чтобы обойти эту проблему, просто убедитесь, что вы запустили код кода взаимодействия BLE (устройство # connectGatt, connect, disconnect и т.д.) В UIThread (с обработчиком, локальной службой или Activity # runOnUiThread). Следуйте этому правилу, и вы, надеюсь, избежите этой ужасной проблемы.

Глубоко в нашей библиотеке, я только имел доступ к контексту приложения. Вы можете создать обработчик из контекста, который будет помещаться в основной поток, используя new Handler(ctx.getMainLooper());

Если вы столкнулись с другими проблемами подключения, разверните образец приложения в samples\android-18\legacy\BluetoothLeGatt и посмотрите, работает ли это приложение. Это было своего рода базой для понимания того, что BLE действительно работает с моим периферийным устройством, и дал мне надежду, что, если я выкопаю достаточно в нашей библиотеке, я в конце концов найду ответ.

РЕДАКТИРОВАТЬ: Я не видел эту проблему "Не удалось зарегистрировать обратный вызов" на Nexus 4, Nexus 5 или Nexus 7 2013 при использовании фоновых потоков для выполнения операций BLE. Это может быть просто проблемой в реализации Samsungs 4.3.

Ответ 2

Итак, моя проблема заключалась в использовании рекурсивной службы. connectGatt отлично работал с lollipop, но более старые версии возвратили null. работа на основной теме решила проблему. Это мое решение:

public void connectToDevice( String deviceAddress) {
    mDeviceAddress = deviceAddress;
    final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(mDeviceAddress);

    Handler handler = new Handler(Looper.getMainLooper());
    handler.post(new Runnable() {
        @Override
        public void run() {


            if (device != null) {

                mGatt = device.connectGatt(getApplicationContext(), true, mGattCallback);
                scanLeDevice(false);// will stop after first device detection
            }
        }
    });
}

Ответ 3

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

Вот список вещей, которые нужно сделать:

  • Убедитесь, что вы используете новый обработчик (Looper.getMainLooper()). post (новый Runnable) при любой gatt-операции (подключитесь, отключите, закройте), а также на операции сканера (startScan, stopScan и т.д.).

  • Существует условие гонки для прямого подключения на Android 6 (или, может быть, 5), поэтому попробуйте подключить gatt следующим образом:

     new Handler(getContext().get().getMainLooper()).post(() -> {
         if (CommonHelper.isNOrAbove()) {
            connectedGatt = connectedBLEDevice.connectGatt(context.get(), true, gattCallback, BluetoothDevice.TRANSPORT_AUTO);
             Timber.tag("HED-BT").d("Connecting BLE after N");
         } else {   
            try {
                Method connectGattMethod = connectedBLEDevice.getClass().getMethod("connectGatt", Context.class, boolean.class, BluetoothGattCallback.class, int.class);
                 connectedGatt = (BluetoothGatt) connectGattMethod.invoke(connectedBLEDevice, context.get(), false, gattCallback, BluetoothDevice.TRANSPORT_AUTO);
                 Timber.tag("HED-BT").d("Connecting BLE before N");
             } catch (Exception e) {
                 failedConnectingBLE();
             }
         }
     });
    
  • При отключении gatt сначала вызовите функцию disconnect() и закройте() в процедуре GattCallback.

Ответ 4

Чтобы автоматически подключаться к устройству Bluetooth, т.е. без явного ввода пользователем, как я пытался это сделать, требуется разрешение BLUETOOTH_PRIVILEDGE. Однако это недоступно для сторонних приложений, поэтому мой код не удался. Добавление опции меню для подключения и использования одного и того же кода отлично работает.

http://developer.android.com/reference/android/Manifest.permission.html#BLUETOOTH_PRIVILEGED