stackoverflow 上的Android BLE API: GATT Notification not received一点感想

大家可以先看一下starkoverflow的一个讨论(时间是两年前的):

http://stackoverflow.com/questions/17910322/android-ble-api-gatt-notification-not-received


大致内容就是安卓上的app明显调用了

public boolean setCharacteristicNotification (BluetoothGattCharacteristic characteristic, boolean enable)

的接口,却收不到gatt server发过来的notification。

让我们先看看这个接口的解释:

Enable or disable notifications/indications for a given characteristic.

Once notifications are enabled for a characteristic, a onCharacteristicChanged(BluetoothGatt, BluetoothGattCharacteristic) callback will be triggered if the remote device indicates that the given characteristic has changed.

Requires BLUETOOTH permission.

Parameters
characteristic	The characteristic for which to enable notifications
enable	Set to true to enable notifications/indications
Returns
true, if the requested notification status was set successfully

说的很明显啊,当你enable一个characteristic的notification之后,一旦远端相应的characteristic的值改变,则一个callback函数
onCharacteristicChanged
就会在本地被调用, 还是符合一般逻辑的,即client告诉server,你如果某个值有变化的话请通知我。

可是如果只是这样世界就完美了,也就不会有那个提问了。调用完这个函数之后,其实gatt server并没有发生什么,这个函数只是在手机本地设置了一下,竟然没有和远端交互。我们可以来看bluedroid中的代码:

/*******************************************************************************
**
** Function         BTA_GATTC_RegisterForNotifications
**
** Description      This function is called to register for notification of a service.
**
** Parameters       client_if - client interface.
**                  bda - target GATT server.
**                  p_char_id - pointer to GATT characteristic ID.
**
** Returns          OK if registration succeed, otherwise failed.
**
*******************************************************************************/
tBTA_GATT_STATUS BTA_GATTC_RegisterForNotifications (tBTA_GATTC_IF client_if,
                                                     BD_ADDR bda,
                                                     tBTA_GATTC_CHAR_ID *p_char_id)
{
    tBTA_GATTC_RCB      *p_clreg;
    tBTA_GATT_STATUS    status = BTA_GATT_ILLEGAL_PARAMETER;
    UINT8               i;

    if (!p_char_id)
    {
        APPL_TRACE_ERROR("deregistration failed, unknow char id");
        return status;
    }

    if ((p_clreg = bta_gattc_cl_get_regcb(client_if)) != NULL)
    {
        for (i = 0; i < BTA_GATTC_NOTIF_REG_MAX; i ++)
        {
            if ( p_clreg->notif_reg[i].in_use &&
                 !memcmp(p_clreg->notif_reg[i].remote_bda, bda, BD_ADDR_LEN) &&
                  bta_gattc_charid_compare(&p_clreg->notif_reg[i].char_id, p_char_id))
            {
                APPL_TRACE_WARNING("notification already registered");
                status = BTA_GATT_OK;
                break;
            }
        }
        if (status != BTA_GATT_OK)
        {
            for (i = 0; i < BTA_GATTC_NOTIF_REG_MAX; i ++)
            {
                if (!p_clreg->notif_reg[i].in_use)
                {
                    memset((void *)&p_clreg->notif_reg[i], 0, sizeof(tBTA_GATTC_NOTIF_REG));

                    p_clreg->notif_reg[i].in_use = TRUE;
                    memcpy(p_clreg->notif_reg[i].remote_bda, bda, BD_ADDR_LEN);

                    p_clreg->notif_reg[i].char_id.srvc_id.is_primary = p_char_id->srvc_id.is_primary;
                    bta_gattc_cpygattid(&p_clreg->notif_reg[i].char_id.srvc_id.id, &p_char_id->srvc_id.id);
                    bta_gattc_cpygattid(&p_clreg->notif_reg[i].char_id.char_id, &p_char_id->char_id);

                    status = BTA_GATT_OK;
                    break;
                }
            }
            if (i == BTA_GATTC_NOTIF_REG_MAX)
            {
                status = BTA_GATT_NO_RESOURCES;
                APPL_TRACE_ERROR("Max Notification Reached, registration failed.");
            }
        }
    }
    else
    {
        APPL_TRACE_ERROR("Client_if: %d Not Registered", client_if);
    }

    return status;
}


我们可以看到,这个函数首先判断characteristic是否合法,之后判断是否超过了注册的notification的数量(15个),之后是把所要notify的service以及characteristic记录在本地,然后就没有了然后了。这一次搞得上层的app以为gatt server已经收到了这个注册通知。其实,gatt server啥都没有收到。

还是要看core spec:


然后再看section3.3.3 写道:

A client may write this configuration descriptor to control the configuration of
this characteristic on the server for the client.

也就是说,client可以用来通过写入一个characteristic的descriptor的值,然后来控制server在这个characteristic变化的时候,是否通知client。

好吧其实一般的思维即是,我调用了前面的接口之后,stack应该办上面设置descriptor的事儿,没有想到完全是两码事……

所以,最终还需要重新写一下这个descriptor,这完全在google的API文档里没有提到嘛,当然在google的例子里面是提到了。可是毕竟会有人没去看这个东西。


对于不熟悉蓝牙的同学来讲是个很大的坑。所以下面这个接口

public boolean writeDescriptor (BluetoothGattDescriptor descriptor)


很重要。



你可能感兴趣的:(stackoverflow 上的Android BLE API: GATT Notification not received一点感想)