安卓牛轧糖(超过 7.0.0)上的 BLE(蓝牙低功耗)无法读取数据



首先,我的应用无法使用ble读取牛轧糖的数据我正在使用Bluenrg-MS模块与设备连接。到棉花糖上的棉花糖法,我可以接收数据。但是超过7.0.0 onchacteristicchanged方法从未调用。

我搜索此问题,有人告诉我添加此代码。

BluetoothGattDescriptor descriptor = characteristic.getDescriptor(CLIENT_UUID);
        if (descriptor != null) {
            descriptor.setValue(enabled ? BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE : BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE);
            mBluetoothGatt.writeDescriptor(descriptor);
        }

,但我不知道该放在client_uuid中。

这是我的所有代码。

public class BleManager {
private static final String TAG = "BleManager";
static final private UUID CCCD_ID = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb");
public static final int STATE_ERROR = -1;
public static final int STATE_NONE = 0;     // Initialized
public static final int STATE_IDLE = 1;     // Not connected
public static final int STATE_SCANNING = 2; // Scanning
public static final int STATE_CONNECTING = 13;  // Connecting
public static final int STATE_CONNECTED = 16;   // Connected
public static final int MESSAGE_STATE_CHANGE = 1;
public static final int MESSAGE_READ = 2;
public static final int MESSAGE_WRITE = 3;
public static final int MESSAGE_DEVICE_NAME = 4;
public static final int MESSAGE_TOAST = 5;
public static final long SCAN_PERIOD = 5*1000;
private static Context mContext = null;
private static BleManager mBleManager = null;
private final Handler mHandler;
private final BluetoothAdapter mBluetoothAdapter;
private BluetoothAdapter.LeScanCallback mLeScanCallback = null;
private ArrayList<BluetoothDevice> mDeviceList = new ArrayList<BluetoothDevice>();
private BluetoothDevice mDefaultDevice = null;
private BluetoothGatt mBluetoothGatt = null;
private ArrayList<BluetoothGattService> mGattServices 
        = new ArrayList<BluetoothGattService>();
private ArrayList<BluetoothGattCharacteristic> mGattCharacteristics 
        = new ArrayList<BluetoothGattCharacteristic>();
private ArrayList<BluetoothGattCharacteristic> mWritableCharacteristics 
        = new ArrayList<BluetoothGattCharacteristic>();
private BluetoothGattCharacteristic mDefaultChar = null;
private int mState = -1;
/**
 * Constructor. Prepares a new Bluetooth session.
 * @param context  The UI Activity Context
 * @param h  A Listener to receive messages back to the UI Activity
 */
private BleManager(Context context, Handler h) {
    mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
    mState = STATE_NONE;
    mHandler = h;
    mContext = context;
    if(mContext == null)
        return;
}
public synchronized static BleManager getInstance(Context c, Handler h) {
    if(mBleManager == null)
        mBleManager = new BleManager(c, h);
    return mBleManager;
}
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
public synchronized void finalize() {
    if (mBluetoothAdapter != null) {
        mState = STATE_IDLE;
        mBluetoothAdapter.stopLeScan(mLeScanCallback);
        disconnect();
    }
    mDefaultDevice = null;
    mBluetoothGatt = null;
    mDefaultService = null;
    mGattServices.clear();
    mGattCharacteristics.clear();
    mWritableCharacteristics.clear();
    if(mContext == null)
        return;
}
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
private void stopScanning() {
    if(mState < STATE_CONNECTING) {
        mState = STATE_IDLE;
        mHandler.obtainMessage(MESSAGE_STATE_CHANGE, STATE_IDLE, 0).sendToTarget();
    }
    mBluetoothAdapter.stopLeScan(mLeScanCallback);
}
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
private int checkGattServices(List<BluetoothGattService> gattServices) {
    if (mBluetoothAdapter == null || mBluetoothGatt == null) {
        Log.d(TAG, "# BluetoothAdapter not initialized");
        return -1;
    }
    for (BluetoothGattService gattService : gattServices) {
        Log.d(TAG, "# GATT Service: "+gattService.toString());
        Toast.makeText(mContext, "" + gattService.toString(), Toast.LENGTH_SHORT).show();
        mGattServices.add(gattService);
        List<BluetoothGattCharacteristic> gattCharacteristics = gattService.getCharacteristics();
        for (BluetoothGattCharacteristic gattCharacteristic : gattCharacteristics) {
            Toast.makeText(mContext, "" + gattCharacteristic.toString(), Toast.LENGTH_SHORT).show();
            mGattCharacteristics.add(gattCharacteristic);
            Log.d(TAG, "# GATT Char: "+gattCharacteristic.toString());
            boolean isWritable = isWritableCharacteristic(gattCharacteristic);
            if(isWritable) {
                mWritableCharacteristics.add(gattCharacteristic);
            }
            boolean isReadable = isReadableCharacteristic(gattCharacteristic); 
            if(isReadable) {
                readCharacteristic(gattCharacteristic);
            }
            if(isNotificationCharacteristic(gattCharacteristic)) {
                setCharacteristicNotification(gattCharacteristic, true);
                if(isWritable && isReadable) {
                    mDefaultChar = gattCharacteristic;
                }
            }
        }
    }
    return mWritableCharacteristics.size();
}
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
private boolean isWritableCharacteristic(BluetoothGattCharacteristic chr) {
    if(chr == null) return false;
    final int charaProp = chr.getProperties();
    if (((charaProp & BluetoothGattCharacteristic.PROPERTY_WRITE) |
            (charaProp & BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE)) > 0) {
        Log.d(TAG, "# Found writable characteristic");
        return true;
    } else {
        Log.d(TAG, "# Not writable characteristic");
        return false;
    }
}
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
private boolean isReadableCharacteristic(BluetoothGattCharacteristic chr) {
    if(chr == null) return false;
    final int charaProp = chr.getProperties();
    if((charaProp & BluetoothGattCharacteristic.PROPERTY_READ) > 0) {
        Log.d(TAG, "# Found readable characteristic");
        return true;
    } else {
        Log.d(TAG, "# Not readable characteristic");
        return false;
    }
}
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
private boolean isNotificationCharacteristic(BluetoothGattCharacteristic chr) {
    if(chr == null) return false;
    final int charaProp = chr.getProperties();
    if((charaProp & BluetoothGattCharacteristic.PROPERTY_NOTIFY) > 0) {
        Log.d(TAG, "# Found notification characteristic");
        return true;
    } else {
        Log.d(TAG, "# Not notification characteristic");
        return false;
    }
}
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
public void readCharacteristic(BluetoothGattCharacteristic characteristic) {
    if (mBluetoothAdapter == null || mBluetoothGatt == null) {
        Log.d(TAG, "# BluetoothAdapter not initialized");
        return;
    }
    mBluetoothGatt.readCharacteristic(characteristic);
}
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
public void setCharacteristicNotification(BluetoothGattCharacteristic characteristic,
                                          boolean enabled) {
    if (mBluetoothAdapter == null || mBluetoothGatt == null) {
        Log.d(TAG, "# BluetoothAdapter not initialized");
        return;
    }
    mBluetoothGatt.setCharacteristicNotification(characteristic, enabled);
    BluetoothGattDescriptor descriptor = characteristic.getDescriptor(CCCD_ID);
    if (descriptor != null) {
        descriptor.setValue(enabled ? BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE : BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE);
        mBluetoothGatt.writeDescriptor(descriptor);
    }
}

public void setScanCallback(BluetoothAdapter.LeScanCallback cb) {
    mLeScanCallback = cb;
}
public int getState() {
    return mState;
}
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
public boolean scanLeDevice(final boolean enable) {
    boolean isScanStarted = false;
    if (enable) {
        if(mState == STATE_SCANNING)
            return false;
        if(mBluetoothAdapter.startLeScan(mLeScanCallback)) {
            mState = STATE_SCANNING;
            mDeviceList.clear();
            mHandler.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        stopScanning();
                    }
                }, SCAN_PERIOD);
            mHandler.obtainMessage(MESSAGE_STATE_CHANGE, STATE_SCANNING, 0).sendToTarget();
            isScanStarted = true;
        }
    } else {
        if(mState < STATE_CONNECTING) {
            mState = STATE_IDLE;
            mHandler.obtainMessage(MESSAGE_STATE_CHANGE, STATE_IDLE, 0).sendToTarget();
        }
        stopScanning();
    }
    return isScanStarted;
}
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
public boolean connectGatt(Context c, boolean bAutoReconnect, BluetoothDevice device) {
    if(c == null || device == null)
        return false;
    mGattServices.clear();
    mGattCharacteristics.clear();
    mWritableCharacteristics.clear();
    mBluetoothGatt = device.connectGatt(c, bAutoReconnect, mGattCallback);
    mDefaultDevice = device;
    mState = STATE_CONNECTING;
    mHandler.obtainMessage(MESSAGE_STATE_CHANGE, STATE_CONNECTING, 0).sendToTarget();
    return true;
}
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
public boolean connectGatt(Context c, boolean bAutoReconnect, String address) {
    if(c == null || address == null)
        return false;
    if(mBluetoothGatt != null && mDefaultDevice != null
            && address.equals(mDefaultDevice.getAddress())) {
         if (mBluetoothGatt.connect()) {
             mState = STATE_CONNECTING;
             return true;
         }
    }
    BluetoothDevice device = 
            BluetoothAdapter.getDefaultAdapter().getRemoteDevice(address);
    if (device == null) {
        Log.d(TAG, "# Device not found.  Unable to connect.");
        return false;
    }
    mGattServices.clear();
    mGattCharacteristics.clear();
    mWritableCharacteristics.clear();
    mBluetoothGatt = device.connectGatt(c, bAutoReconnect, mGattCallback);
    mDefaultDevice = device;
    mState = STATE_CONNECTING;
    mHandler.obtainMessage(MESSAGE_STATE_CHANGE, STATE_CONNECTING, 0).sendToTarget();
    return true;
}
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
public void disconnect() {
    if (mBluetoothAdapter == null || mBluetoothGatt == null) {
        Log.d(TAG, "# BluetoothAdapter not initialized");
        return;
    }
    mBluetoothGatt.disconnect();
}
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
public boolean write(BluetoothGattCharacteristic chr, byte[] data) {
    if (mBluetoothGatt == null) {
        Log.d(TAG, "# BluetoothGatt not initialized");
        return false;
    }
    BluetoothGattCharacteristic writableChar = null;
    if(chr == null) {
        if(mDefaultChar == null) {
            for(BluetoothGattCharacteristic bgc : mWritableCharacteristics) {
                if(isWritableCharacteristic(bgc)) {
                    writableChar = bgc;
                }
            }
            if(writableChar == null) {
                Log.d(TAG, "# Write failed - No available characteristic");
                return false;
            }
        } else {
            if(isWritableCharacteristic(mDefaultChar)) {
                Log.d(TAG, "# Default GattCharacteristic is PROPERY_WRITE | PROPERTY_WRITE_NO_RESPONSE");
                writableChar = mDefaultChar;
            } else {
                Log.d(TAG, "# Default GattCharacteristic is not writable");
                mDefaultChar = null;
                return false;
            }
        }
    } else {
        if (isWritableCharacteristic(chr)) {
            Log.d(TAG, "# user GattCharacteristic is PROPERY_WRITE | PROPERTY_WRITE_NO_RESPONSE");
            writableChar = chr;
        } else {
            Log.d(TAG, "# user GattCharacteristic is not writable");
            return false;
        }
    }
    writableChar.setValue(data);
    writableChar.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT);
    mBluetoothGatt.writeCharacteristic(writableChar);
    mDefaultChar = writableChar;
    return true;
}
private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
    @Override
    public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
        if (newState == BluetoothProfile.STATE_CONNECTED) {
            mState = STATE_CONNECTED;
            Log.d(TAG, "# Connected to GATT server.");
            mHandler.obtainMessage(MESSAGE_STATE_CHANGE, STATE_CONNECTED, 0).sendToTarget();
            gatt.discoverServices();
        } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
            mState = STATE_IDLE;
            Log.d(TAG, "# Disconnected from GATT server.");
            mHandler.obtainMessage(MESSAGE_STATE_CHANGE, STATE_IDLE, 0).sendToTarget();
            mBluetoothGatt = null;
            mGattServices.clear();
            mDefaultService = null;
            mGattCharacteristics.clear();
            mWritableCharacteristics.clear();
            mDefaultChar = null;
            mDefaultDevice = null;
        }
    }
    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
    @Override
    public void onServicesDiscovered(BluetoothGatt gatt, int status) {
        if (status == BluetoothGatt.GATT_SUCCESS) {
            Log.d(TAG, "# New GATT service discovered.");
            checkGattServices(gatt.getServices());
        } else {
            Log.d(TAG, "# onServicesDiscovered received: " + status);
        }
    }
    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
    @Override
    public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
        if (status == BluetoothGatt.GATT_SUCCESS) {
            // We've received data from remote
            Log.d(TAG, "# Read characteristic: "+characteristic.toString());
            final byte[] data = characteristic.getValue();
            if (data != null && data.length > 0) {
                final StringBuilder stringBuilder = new StringBuilder(data.length);
                stringBuilder.append(data);
                Log.d(TAG, stringBuilder.toString());
                mHandler.obtainMessage(MESSAGE_READ, byteArrayToHex(data)).sendToTarget();
            }
            if(mDefaultChar == null && isWritableCharacteristic(characteristic)) {
                mDefaultChar = characteristic;
            }
        }
    }
    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
    @Override
    public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
        // We've received data from remote
        Log.d(TAG, "# onCharacteristicChanged: "+characteristic.toString());
        final byte[] data = characteristic.getValue();
        if (data != null && data.length > 0) {
            final StringBuilder stringBuilder = new StringBuilder(data.length);
            //for(byte byteChar : data)
            //  stringBuilder.append(String.format("%02X ", byteChar));
            stringBuilder.append(data);
            Log.d(TAG, stringBuilder.toString());
            mHandler.obtainMessage(MESSAGE_READ, byteArrayToHex(data)).sendToTarget();
        }
        if(mDefaultChar == null && isWritableCharacteristic(characteristic)) {
            mDefaultChar = characteristic;
        }
    }
};
String byteArrayToHex(byte[] a) {
    StringBuilder sb = new StringBuilder();
    for(final byte b: a)
        sb.append(String.format("%02x", b&0xff));
    return sb.toString();
}}

请在下面尝试函数,以启用有关蓝牙低能特征的通知。我没有注意到Android在7.0.0以上的任何麻烦。

当您订阅特征更新时,应在 onCharacteristicChangedCallback()中获得更新值。确保实际在外围更新了值;)

private void enableNotifications(BluetoothGatt bluetoothGatt, BluetoothGattCharacteristic characteristic ){
    UUID CLIENT_CHARACTERISTIC_CONFIG = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb");
    byte[] payload =  BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE;
    bluetoothGatt.setCharacteristicNotification(characteristic, true);
    BluetoothGattDescriptor descriptor = characteristic.getDescriptor(
            CLIENT_CHARACTERISTIC_CONFIG);
    if (descriptor == null){
        Log.w(TAG, "Notification not supported for characteristic");
        return;
    }
    descriptor.setValue(payload);
    bluetoothGatt.writeDescriptor(descriptor);
}

最新更新