Android nougat(超过7.0.0)的BLE(蓝牙低功耗)无法读取数据

与天地兮比寿,与日月兮齐光。这篇文章主要讲述Android nougat(超过7.0.0)的BLE(蓝牙低功耗)无法读取数据相关的知识,希望能为你提供帮助。
首先,我的应用程序无法使用BLE读取牛轧糖中的数据我正在使用BlueNRG-MS模块与设备连接。调用Marshmallow onCharacteristicChanged方法,我可以接收数据。但超过7.0.0 onCharacteristicChanged方法从未调用过。
我搜索了这个,有人告诉我添加这个代码。

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; // Connectedpublic 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 contextThe UI Activity Context * @param hA 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 = https://www.songbingjia.com/android/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 = https://www.songbingjia.com/android/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以上的任何麻烦。
【Android nougat(超过7.0.0)的BLE(蓝牙低功耗)无法读取数据】当您订阅特征更新时,您应该在onCharacteristicChanged Callback()中获取更新的值。确保,外围设备上的值实际更新; )
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); }


    推荐阅读