Android ble setCharactersticNotification() 依然无法收到通知


参看 http://stackoverflow.com/questions/22817005/why-does-setcharactersticnotification-not-actually-enable-notifications
参看 http://stackoverflow.com/questions/17910322/android-ble-api-gatt-notification-not-received
深入阅读可以参看我师傅几年前的译文:
http://blog.csdn.net/likebamboo/article/details/27485987

原文:
It seems like having a Client Characteristic Config Descriptor (CCCD) characterstic is the standard way to control characteristic notification, so why doesn’t setCharactersticNotification() take care of writing to it? And since it doesn’t do that, what does setCharacteristicNotificaion() actually do?

译文:
看起来似乎使用一个CCCD(Client Characteristic Config Descriptor)特征就可以控制特征的通知事件,然而为什么setCharactersticNotification()无法应付它呢?如果它不是这个作用,那它是什么作用?

原文:
I think is a litte bit late for give an answer but today I had the same doubt and I found a clear answer.
Using setCharacteristicNotification() you enable notification localy (on android device) and setting CCC descriptor to ENABLE_NOTIFICATION_VALUE you enable notification on ble peripheral.
In fact for enabling CCC notification you have to use setValue() and writeDescriptor() that are methods used for writing characteristics (in this case characteristics descriptors) to remote device.
I found this on: http://processors.wiki.ti.com/index.php/SensorTag_User_Guide

译文:
我认为我给出的回答有点晚了,但是我现在也有一个相同的疑问,并且我找到了一个漂亮的回答。使用setCharacteristicNotification()你可以启用本地通知(在安卓设备上),并且通过设置CCCD为ENABLE_NOTIFICATION_VALUE,你可以启用ble周边的通知。事实上,要启用CCC通知,你必须使用setValue()和writeDescriptor(),该方法用于将特征值(在这种情况下是特征描述)写入远程设备。我是在以下网站找到的http://processors.wiki.ti.com/index.php/SensorTag_User_Guide

因此,解决方案为

boolean isEnableNotification = gatt.setCharacteristicNotification(characteristicRead, true);
if(isEnableNotification) {
    List<BluetoothGattDescriptor> descriptorList = characteristicRead.getDescriptors();
    if(descriptorList != null && descriptorList.size() > 0) {
        for(BluetoothGattDescriptor descriptor : descriptorList) {
            descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
            gatt.writeDescriptor(descriptor);
        }
    }
}

查看源码进行分析:
对比writeCharacteristic()方法,查看setCharacteristicNotification()的源码可以发现,都是调用IBluetoothGatt,使用AIDL的方式调用系统服务的接口。其实具体实现方法我也看不到。

/**
     * Writes a given characteristic and its values to the associated remote device.
     *
     * <p>Once the write operation has been completed, the
     * {@link BluetoothGattCallback#onCharacteristicWrite} callback is invoked,
     * reporting the result of the operation.
     *
     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
     *
     * @param characteristic Characteristic to write on the remote device
     * @return true, if the write operation was initiated successfully
     */
    public boolean writeCharacteristic(BluetoothGattCharacteristic characteristic) {
        if ((characteristic.getProperties() & BluetoothGattCharacteristic.PROPERTY_WRITE) == 0
            && (characteristic.getProperties() &
                BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE) == 0) return false;

        if (VDBG) Log.d(TAG, "writeCharacteristic() - uuid: " + characteristic.getUuid());
        if (mService == null || mClientIf == 0 || characteristic.getValue() == null) return false;

        BluetoothGattService service = characteristic.getService();
        if (service == null) return false;

        BluetoothDevice device = service.getDevice();
        if (device == null) return false;

        synchronized(mDeviceBusy) {
            if (mDeviceBusy) return false;
            mDeviceBusy = true;
        }

        try {
            mService.writeCharacteristic(mClientIf, device.getAddress(),
                service.getType(), service.getInstanceId(),
                new ParcelUuid(service.getUuid()), characteristic.getInstanceId(),
                new ParcelUuid(characteristic.getUuid()),
                characteristic.getWriteType(), AUTHENTICATION_NONE,
                characteristic.getValue());
        } catch (RemoteException e) {
            Log.e(TAG,"",e);
            mDeviceBusy = false;
            return false;
        }

        return true;
    }
/**
 * Enable or disable notifications/indications for a given characteristic.
 *
 * <p>Once notifications are enabled for a characteristic, a
 * {@link BluetoothGattCallback#onCharacteristicChanged} callback will be
 * triggered if the remote device indicates that the given characteristic
 * has changed.
 *
 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
 *
 * @param characteristic The characteristic for which to enable notifications
 * @param enable Set to true to enable notifications/indications
 * @return true, if the requested notification status was set successfully
 */
public boolean setCharacteristicNotification(BluetoothGattCharacteristic characteristic,
                                          boolean enable) {
    if (DBG) Log.d(TAG, "setCharacteristicNotification() - uuid: " + characteristic.getUuid()
                     + " enable: " + enable);
    if (mService == null || mClientIf == 0) return false;

    BluetoothGattService service = characteristic.getService();
    if (service == null) return false;

    BluetoothDevice device = service.getDevice();
    if (device == null) return false;

    try {
        mService.registerForNotification(mClientIf, device.getAddress(),
            service.getType(), service.getInstanceId(),
            new ParcelUuid(service.getUuid()), characteristic.getInstanceId(),
            new ParcelUuid(characteristic.getUuid()),
            enable);
    } catch (RemoteException e) {
        Log.e(TAG,"",e);
        return false;
    }
    return true;
}

我查了一下,descriptor定义了如下3个值

/**
 * Value used to enable notification for a client configuration descriptor
 */
public static final byte[] ENABLE_NOTIFICATION_VALUE = {0x01, 0x00};
/**
 * Value used to enable indication for a client configuration descriptor
 */
public static final byte[] ENABLE_INDICATION_VALUE = {0x02, 0x00};
/**
 * Value used to disable notifications or indicatinos
 */
public static final byte[] DISABLE_NOTIFICATION_VALUE = {0x00, 0x00};

indication 我不知道是什么作用,有知道的希望不吝赐教

基于以上内容,个人猜测之所以BLE要这么设计和QQ群助手的实现方式有点像:如果ENABLE_NOTIFICATION_VALUE启用ble周边的特征通知,而本地未注册监听,那么本地就会一直缓存这些特征的改变值到一个队列,一旦本地注册监听setCharacteristicNotification(),依然会收到以前的通知(这就像QQ群助手中的——接受但不提示)。

  • 6
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值