GATTcallback无法注册

我试图编写一个应用程序通过蓝牙低功耗发送消息,然后通过UART在外设中传递消息。 我已经按照这里的步骤,应用程序扫描并find设备成功。 但是,使用BluetoothGatt = BluetoothDevice.connectGatt(context,autoconnect,callback)方法的连接失败,logcat说“无法注册callback”。

呼叫来自:

//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); } }; 

而加特callback:

 //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 

有趣的是,我的外设移动到“连接”状态(我有指示灯),我可以通过演示应用程序或PC BLE软件狗从同一部手机连接到它。 任何想法赞赏。

[编辑] connectGatt方法返回null,我猜是预期的。

[编辑]在检查API 18源代码,似乎提供了“无法注册callback”消息,因为方法registerApp()返回false,因为IBluetoothGatt“mService”的registerClient()方法抛出远程exception,可能在线:

 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 

因为在下一行中的日志消息是从来没有看到。 所以它可能是一个权限的事情,除了应用程序具有蓝牙和bluetooth_admin权限。

我终于明白了这个问题。 我使用的设备是一个三星Galaxy S4和实际的问题(感谢Wibble在你的答案指导,但你的结论略有偏差)似乎是一个线程问题。

在Wibble的回答中,他表示添加一个连接button可以解决他的问题。 我开始想知道为什么这很重要,而且我也可以在整个会话期间连接和断开连接,而不需要使用后台工作线程的GUIbutton。 只要我强制closures我的应用程序,重新启动它,并尝试连接,我开始收到错误“无法注册callback”。 没有任何工作了。 我差点把头发拉出来

在三星的论坛中查看我的post ,了解我确切问题的更多细节。

解决scheme:为了解决这个问题,只要确保在UIThread(使用处理程序,本地服务或Activity#runOnUiThread)中运行任何BLE交互代码(device#connectGatt,connect,disconnect等)。 按照这个经验法则,你会希望避免这个可怕的问题。

在我们的图书馆深处,我只能访问应用程序上下文。 你可以通过使用new Handler(ctx.getMainLooper());在上下文中创build一个处理程序new Handler(ctx.getMainLooper());

如果您遇到其他连接问题,请将示例应用程序部署在samples\android-18\legacy\BluetoothLeGatt并查看该应用程序是否可用。 这实际上是我实现BLE的基准,实际上与我的外设一起工作,并给了我希望,如果我在我们的图书馆挖足够了,我最终会find答案。

编辑:当使用后台线程执行BLE操作时,我没有看到在Nexus 4,Nexus 5或Nexus 7 2013上的“无法注册callback”问题。 三星4.3的实现可能只是一个问题。

所以,我的问题是从recursion服务运行它。 connectGatt与棒棒糖一起工作良好,但旧版本返回null。 在主线程上运行解决了这个问题。 这是我的解决scheme:

 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 } } }); } 

我也可以确认罗先生是首先检查的答案。 我testing了很多设备,其中一些从辅助线程运行时performance良好。 有些可能会阻止一段时间,行为是不可预测的。

这里是要做的事情列表:

  1. 制造商确保你使用新的处理程序(Looper.getMainLooper())。post(新的Runnable) 在任何gatt操作 (连接,断开,closures),但也扫描仪操作 (startScan,stopScan等)。

  2. 在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(); } } }); 
  3. 断开gatt时,首先调用disconnect(),然后在GattCallback例程中closures()。

为了自动连接到蓝牙设备,即没有明确的用户input,正如我试图做的那样,需要权限BLUETOOTH_PRIVILEDGE。 但是,这不适用于第三方应用程序,所以我的代码失败。 添加一个菜单选项来连接和使用相同的代码工作正常。

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