首先,我的应用程序无法使用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; // 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以上的任何麻烦。
当您订阅特征更新时,您应该在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);
}