Android Ble低功耗蓝牙开发
一、新建项目
在Android Studio中新建一个项目,如下图所示:
选择No Activity,然后点击Next
点击Finish,完成项目创建。
1、配置build.gradle
在android{}闭包中添加viewBinding,用于获取控件
buildFeatures {
viewBinding true
}
添加完成后,点击同步Sync
2、配置清单文件AndroidManifest.xml
在清单文件中,添加蓝牙相关权限如下:
二、搜索蓝牙设备
搜索蓝牙设备之前,需要检测手机蓝牙是否已经打开,如果未开启蓝牙,需要先开启蓝牙,才能搜索蓝牙设备。
1、创建MainActivity
在项目包名的位置,右键选择创建Empty Views Activity
勾选Launcher Activity,然后点击Finish
构建activity_main.xml布局:
MainActivity中通过ViewBinding绑定布局,代码如下:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityMainBinding mBinding = ActivityMainBinding.inflate(getLayoutInflater());
setContentView(mBinding.getRoot());
}
}
2、开启蓝牙
MainActivity中添加点击事件:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityMainBinding mBinding = ActivityMainBinding.inflate(getLayoutInflater());
setContentView(mBinding.getRoot());
mBinding.btnStartScan.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
}
});
}
}
新建个BleUtils工具类,并添加检测蓝牙是否开启、检测是否有权限的方法:
public class BleUtils {
/**
* 检测是否已经开启蓝牙
*/
public static boolean isOpenBle(Context context) {
BluetoothManager manager = (BluetoothManager) context.getSystemService(Context.BLUETOOTH_SERVICE);
if (manager != null) {
BluetoothAdapter adapter = manager.getAdapter();
if (adapter != null) {
return adapter.isEnabled();
}
}
return false;
}
/**
* 检测是否有权限
*/
public static boolean hasPermission(Context context, String permission) {
return context.checkSelfPermission(permission) == PackageManager.PERMISSION_GRANTED;
}
}
然后在搜索蓝牙设备的点击事件中检测手机是否已开启蓝牙,已开启蓝牙,可以搜索蓝牙设备,未开启蓝牙,需要先开启蓝牙
mBinding.btnStartScan.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//判断是否开启蓝牙
if (!BleUtils.isOpenBle(mContext)) {
openBle();
} else {//已开启蓝牙
//搜索蓝牙设备
searchBle();
}
}
});
开启蓝牙需要打开蓝牙相关的权限
在build.gradle中引入三方库’com.blankj:utilcodex:1.31.1’,用于权限管理和获取各种工具类
//http://github.com/Blankj/AndroidUtilCode 工具类
implementation 'com.blankj:utilcodex:1.31.1'
在MainActivity中添加开启蓝牙方法:
/**
* 开启蓝牙
*/
@SuppressLint("MissingPermission")
public void openBle() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {//Android12以上添加权限
if (BleUtils.hasPermission(mContext, android.Manifest.permission.BLUETOOTH_CONNECT)) {
//开启蓝牙
Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
} else {
PermissionUtils.permission(Manifest.permission.BLUETOOTH_CONNECT).callback(new PermissionUtils.SimpleCallback() {
@Override
public void onGranted() {
Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
mContext.startActivity(intent);
}
@Override
public void onDenied() {
ToastUtils.showShort("Android12无此权限,无法打开蓝牙");
}
}).request();
}
} else {
Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
mContext.startActivity(intent);
}
}
扫描蓝牙设备前,需要检测扫描蓝牙权限是否开启:
/**
* 搜索蓝牙设备,检测搜索权限
*/
private void searchBle() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {//Android12以上,需要BLUETOOTH_SCAN权限
if (!BleUtils.hasPermission(mContext, Manifest.permission.BLUETOOTH_CONNECT)) {
PermissionUtils.permission(Manifest.permission.BLUETOOTH_CONNECT).callback(new PermissionUtils.SimpleCallback() {
@Override
public void onGranted() {
//开启蓝牙
Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
@Override
public void onDenied() {
ToastUtils.showShort("Android12无此权限,无法打开蓝牙");
}
}).request();
return;
}
if (BleUtils.hasPermission(mContext, Manifest.permission.BLUETOOTH_SCAN)) {
ToastUtils.showShort("扫描蓝牙");
startScan();
} else {
PermissionUtils.permission(Manifest.permission.BLUETOOTH_SCAN).callback(new PermissionUtils.SimpleCallback() {
@Override
public void onGranted() {
//扫描蓝牙
ToastUtils.showShort("扫描蓝牙");
}
@Override
public void onDenied() {
ToastUtils.showShort("Android12无此权限,无法扫描蓝牙");
}
}).request();
}
} else {
if (BleUtils.hasPermission(mContext, Manifest.permission.ACCESS_FINE_LOCATION)) {
ToastUtils.showShort("扫描蓝牙");
startScan();
} else {
PermissionUtils.permission(Manifest.permission.ACCESS_FINE_LOCATION).callback(new PermissionUtils.SimpleCallback() {
@Override
public void onGranted() {
//扫描蓝牙
ToastUtils.showShort("扫描蓝牙");
}
@Override
public void onDenied() {
ToastUtils.showShort("Android12无此权限,无法扫描蓝牙");
}
}).request();
}
}
}
3、扫描搜索蓝牙设备:
/**
* 开始扫描蓝牙设备
*/
@SuppressLint("MissingPermission")
private void startScan() {
BluetoothManager manager = (BluetoothManager) mContext.getSystemService(BLUETOOTH_SERVICE);
mBluetoothAdapter = manager.getAdapter();
if (mBluetoothAdapter != null) {
mScanner = mBluetoothAdapter.getBluetoothLeScanner();
LogUtils.i("startScan");
if (mScanner != null) {
mHandler.removeCallbacks(scanRunnable);
mScanner.startScan(scanCallback);
mHandler.postDelayed(scanRunnable, 10 * 1000L);
}
}
}
/**
* 扫描结果
*/
@SuppressLint("MissingPermission")
private final ScanCallback scanCallback = new ScanCallback() {
@Override
public void onScanResult(int callbackType, ScanResult result) {
super.onScanResult(callbackType, result);
if (result != null) {
BluetoothDevice device = result.getDevice();
int rssi = result.getRssi();
String address = device.getAddress();
ScanDeviceBean scanDeviceBean = new ScanDeviceBean();
scanDeviceBean.setDeviceMac(device.getAddress());
String deviceName = device.getName();
scanDeviceBean.setDeviceName(!TextUtils.isEmpty(deviceName) ? deviceName : "Unknow");
scanDeviceBean.setDeviceRssi(rssi);
}
}
@Override
public void onScanFailed(int errorCode) {
super.onScanFailed(errorCode);
}
};
class StopScanRunnable implements Runnable {
StopScanRunnable() {
}
@Override
public void run() {
stopScan();
}
}
/**
* 停止扫描
*/
@SuppressLint("MissingPermission")
public void stopScan() {
LogUtils.i("stopScan");
try {
if (mScanner != null) {
mHandler.removeCallbacks(scanRunnable);
mScanner.stopScan(scanCallback);
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
其中,ScanDeviceBean为扫描结果实体类:
public class ScanDeviceBean {
private String deviceMac;
private String deviceName;
private int deviceRssi;
public String getDeviceMac() {
return deviceMac;
}
public void setDeviceMac(String deviceMac) {
this.deviceMac = deviceMac;
}
public String getDeviceName() {
return deviceName;
}
public void setDeviceName(String deviceName) {
this.deviceName = deviceName;
}
public int getDeviceRssi() {
return deviceRssi;
}
public void setDeviceRssi(int deviceRssi) {
this.deviceRssi = deviceRssi;
}
}
activity_main.xml中添加RecyclerView,用于展示搜素到的蓝牙设备:
将搜索到的蓝牙设备显示到列表中:
//http://github.com/CymChad/BaseRecyclerViewAdapterHelper
implementation 'com.github.CymChad:BaseRecyclerViewAdapterHelper:3.0.4'
DeviceAdapter :
public class DeviceAdapter extends BaseQuickAdapter {
public DeviceAdapter() {
super(R.layout.item_device);
}
@Override
protected void convert(@NonNull BaseViewHolder baseViewHolder, ScanDeviceBean deviceEntity) {
baseViewHolder.setText(R.id.tv_name, deviceEntity.getDeviceName());
baseViewHolder.setText(R.id.tv_address, deviceEntity.getDeviceMac());
baseViewHolder.setText(R.id.tv_rssi, deviceEntity.getDeviceRssi()+"dBm");
}
}
item_device布局:
蓝牙图标icon_bluetooth.xml:
在MainActivity中展示蓝牙设备列表:
public class MainActivity extends AppCompatActivity {
private Context mContext;
private BluetoothAdapter mBluetoothAdapter;
private BluetoothLeScanner mScanner;
private static final Handler mHandler = new Handler();
private final Runnable scanRunnable = new StopScanRunnable();
private final ArrayList mDeviceList = new ArrayList();
private DeviceAdapter mDeviceAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityMainBinding mBinding = ActivityMainBinding.inflate(getLayoutInflater());
setContentView(mBinding.getRoot());
mContext = getApplicationContext();
mDeviceAdapter = new DeviceAdapter();
mBinding.recyclerView.setAdapter(mDeviceAdapter);
mBinding.btnStartScan.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//判断是否开启蓝牙
if (!BleUtils.isOpenBle(mContext)) {
openBle();
} else {//已开启蓝牙
//搜索蓝牙设备
searchBle();
}
}
});
}
/**
* 开启蓝牙
*/
@SuppressLint("MissingPermission")
public void openBle() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {//Android12以上添加权限
if (BleUtils.hasPermission(mContext, android.Manifest.permission.BLUETOOTH_CONNECT)) {
//开启蓝牙
Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
} else {
PermissionUtils.permission(Manifest.permission.BLUETOOTH_CONNECT).callback(new PermissionUtils.SimpleCallback() {
@Override
public void onGranted() {
Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
mContext.startActivity(intent);
}
@Override
public void onDenied() {
ToastUtils.showShort("Android12无此权限,无法打开蓝牙");
}
}).request();
}
} else {
Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
mContext.startActivity(intent);
}
}
/**
* 搜索蓝牙设备,检测搜索权限
*/
@SuppressLint("MissingPermission")
private void searchBle() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {//Android12以上,需要BLUETOOTH_SCAN权限
if (!BleUtils.hasPermission(mContext, Manifest.permission.BLUETOOTH_CONNECT)) {
PermissionUtils.permission(Manifest.permission.BLUETOOTH_CONNECT).callback(new PermissionUtils.SimpleCallback() {
@Override
public void onGranted() {
//开启蓝牙
Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
@Override
public void onDenied() {
ToastUtils.showShort("Android12无此权限,无法打开蓝牙");
}
}).request();
return;
}
if (BleUtils.hasPermission(mContext, Manifest.permission.BLUETOOTH_SCAN)) {
ToastUtils.showShort("扫描蓝牙");
startScan();
} else {
PermissionUtils.permission(Manifest.permission.BLUETOOTH_SCAN).callback(new PermissionUtils.SimpleCallback() {
@Override
public void onGranted() {
//扫描蓝牙
ToastUtils.showShort("扫描蓝牙");
}
@Override
public void onDenied() {
ToastUtils.showShort("Android12无此权限,无法扫描蓝牙");
}
}).request();
}
} else {
if (BleUtils.hasPermission(mContext, Manifest.permission.ACCESS_FINE_LOCATION)) {
ToastUtils.showShort("扫描蓝牙");
startScan();
} else {
PermissionUtils.permission(Manifest.permission.ACCESS_FINE_LOCATION).callback(new PermissionUtils.SimpleCallback() {
@Override
public void onGranted() {
//扫描蓝牙
ToastUtils.showShort("扫描蓝牙");
}
@Override
public void onDenied() {
ToastUtils.showShort("Android12无此权限,无法扫描蓝牙");
}
}).request();
}
}
}
/**
* 开始扫描蓝牙设备
*/
@SuppressLint("MissingPermission")
private void startScan() {
BluetoothManager manager = (BluetoothManager) mContext.getSystemService(BLUETOOTH_SERVICE);
mBluetoothAdapter = manager.getAdapter();
if (mBluetoothAdapter != null) {
mScanner = mBluetoothAdapter.getBluetoothLeScanner();
LogUtils.i("startScan");
if (mScanner != null) {
mHandler.removeCallbacks(scanRunnable);
mScanner.startScan(scanCallback);
mHandler.postDelayed(scanRunnable, 10 * 1000L);
}
}
}
/**
* 扫描结果
*/
@SuppressLint("MissingPermission")
private final ScanCallback scanCallback = new ScanCallback() {
@Override
public void onScanResult(int callbackType, ScanResult result) {
super.onScanResult(callbackType, result);
if (result != null) {
BluetoothDevice device = result.getDevice();
int rssi = result.getRssi();
String address = device.getAddress();
ScanDeviceBean scanDeviceBean = new ScanDeviceBean();
scanDeviceBean.setDeviceMac(device.getAddress());
String deviceName = device.getName();
scanDeviceBean.setDeviceName(!TextUtils.isEmpty(deviceName) ? deviceName : "Unknow");
scanDeviceBean.setDeviceRssi(rssi);
boolean isContain = false;
for (ScanDeviceBean bean : mDeviceList) {
if (bean.getDeviceMac().equals(scanDeviceBean.getDeviceMac())) {
isContain = true;
break;
}
}
if (!isContain) {
mDeviceList.add(scanDeviceBean);
mDeviceAdapter.setList(mDeviceList);
}
}
}
@Override
public void onScanFailed(int errorCode) {
super.onScanFailed(errorCode);
}
};
class StopScanRunnable implements Runnable {
StopScanRunnable() {
}
@Override
public void run() {
stopScan();
}
}
/**
* 停止扫描
*/
@SuppressLint("MissingPermission")
public void stopScan() {
LogUtils.i("stopScan");
try {
if (mScanner != null) {
mHandler.removeCallbacks(scanRunnable);
mScanner.stopScan(scanCallback);
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
搜索到的蓝牙设备列表如下:
三、连接蓝牙设备
蓝牙设备列表添加点击事件,点击连接蓝牙设备:
mDeviceAdapter.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(@NonNull BaseQuickAdapter adapter, @NonNull View view, int position) {
String deviceMac = mDeviceList.get(position).getDeviceMac();
connectBle(deviceMac);
}
});
/**
* 连接蓝牙设备
*
* @param macAddress 蓝牙设备地址
*/
@SuppressLint("MissingPermission")
public void connectBle(String macAddress) {
if (mBluetoothAdapter != null && !TextUtils.isEmpty(macAddress)) {
BluetoothDevice remoteDevice = mBluetoothAdapter.getRemoteDevice(macAddress);
if (remoteDevice != null) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
//BluetoothDevice.TRANSPORT_AUTO:对于GATT连接到远程双模设备无物理传输优先。
//BluetoothDevice.TRANSPORT_BREDR:GATT连接到远程双模设备优先BR/EDR。
//BluetoothDevice.TRANSPORT_LE:GATT连接到远程双模设备优先BLE。
mBluetoothGatt = remoteDevice.connectGatt(mContext, false, mBleGattCallBack, BluetoothDevice.TRANSPORT_LE);
} else {
mBluetoothGatt = remoteDevice.connectGatt(mContext, false, mBleGattCallBack);
}
}
}
}
连接状态回调:
/**
* 连接状态回调
*/
@SuppressLint("MissingPermission")
class BleGattCallBack extends BluetoothGattCallback {
// @Override
// public void onMtuChanged(BluetoothGatt gatt, int mtu, int status) {
// super.onMtuChanged(gatt, mtu, status);
// if (status == BluetoothGatt.GATT_SUCCESS) {
// LogUtils.e( "request mtu success.约定后的MTU值为:" + mtu);
// } else {
// LogUtils.e( "request mtu failed.");
// }
//
// if (mBluetoothGatt != null) {
// mBluetoothGatt.discoverServices();
// }
// }
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
super.onConnectionStateChange(gatt, status, newState);
LogUtils.i("onConnectionStateChange status " + status + " newState " + newState);
if (newState == BluetoothProfile.STATE_CONNECTED) {
LogUtils.i("蓝牙连接成功,开始发现服务");
// boolean mut = gatt.requestMtu(500);//如有需要可以申请扩容
// LogUtils.i("申请MTU扩容" + mut);
if (mBluetoothGatt != null) {
mBluetoothGatt.discoverServices();
}
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
LogUtils.e("蓝牙连接已断开");
}
}
@Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
super.onServicesDiscovered(gatt, status);
LogUtils.i("onServicesDiscovered status " + status);
if (status == BluetoothGatt.GATT_SUCCESS) {
LogUtils.i("成功获取服务,开始获取服务里的特性");
if (mBluetoothGatt != null) {
List services = mBluetoothGatt.getServices();
for (BluetoothGattService gattService : services) {
LogUtils.d("服务uuid " + gattService.getUuid());
List characteristics = gattService.getCharacteristics();
for (BluetoothGattCharacteristic gattCharacteristic : characteristics) {
int charaProp = gattCharacteristic.getProperties();
StringBuilder stringBuilder = new StringBuilder();
if ((charaProp & BluetoothGattCharacteristic.PROPERTY_READ) > 0) {
stringBuilder.append(" 可读 ");
}
if ((charaProp & BluetoothGattCharacteristic.PROPERTY_WRITE) > 0) {
stringBuilder.append(" 可写 ");
}
if ((charaProp & BluetoothGattCharacteristic.PROPERTY_NOTIFY) < 0) {
stringBuilder.append(" 通知 ");
}
LogUtils.d("特性uuid " + gattCharacteristic.getUuid() + stringBuilder);
}
}
}
} else {
LogUtils.e("服务获取失败");
}
}
@Override
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
super.onCharacteristicRead(gatt, characteristic, status);
//Android12及以下,适用此方法
if (Build.VERSION.SDK_INT = Build.VERSION_CODES.TIRAMISU) {
LogUtils.i("onDescriptorWrite,(Android13及以上)写描述符:" + descriptor.getUuid().toString() + " status:" + status);
} else {
LogUtils.i("onDescriptorWrite,(Android12及以下)写描述符:" + descriptor.getUuid().toString() + " value:" + Arrays.equals(descriptor.getValue(), BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE) + " status:" + status);
}
//Android 13及以上版本,descriptor.getValue()方法已过时,获取的value为null,需要可以通过gatt.readDescriptor(descriptor)获取value(前提是这个特性可读)
if (status == BluetoothGatt.GATT_SUCCESS) {
} else {
}
}
@Override
public void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
super.onDescriptorRead(gatt, descriptor, status);
//Android12及以下,适用此方法
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {//适用于Android12及以下
LogUtils.i("onDescriptorRead,(Android12及以下)读描述符:" + descriptor.getUuid().toString());
if (status == BluetoothGatt.GATT_SUCCESS) {
} else {
}
}
}
@Override
public void onDescriptorRead(@NonNull BluetoothGatt gatt, @NonNull BluetoothGattDescriptor descriptor, int status, @NonNull byte[] value) {
super.onDescriptorRead(gatt, descriptor, status, value);
//Android13及以上,适用此方法
LogUtils.i("onDescriptorRead,(Android13及以上)读描述符:" + descriptor.getUuid().toString());
if (status == BluetoothGatt.GATT_SUCCESS) {
} else {
}
}
@Override
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {//通知特性发生改变
super.onCharacteristicChanged(gatt, characteristic);
if (Build.VERSION.SDK_INT 0) {
String hexValue = BleUtils.bytesToHex(characteristic.getValue());
LogUtils.i("onCharacteristicChanged,(Android12及以下)特性发生改变:" + characteristic.getUuid() + ",值:" + hexValue);
}
}
}
@Override
public void onCharacteristicChanged(@NonNull BluetoothGatt gatt, @NonNull BluetoothGattCharacteristic characteristic, @NonNull byte[] value) {
super.onCharacteristicChanged(gatt, characteristic, value);
//Android13及以上,适用此方法
if (value.length > 0) {
String hexValue = BleUtils.bytesToHex(value);
LogUtils.i("onCharacteristicChanged,(Android13及以上)特性发生改变:" + characteristic.getUuid() + ",值:" + hexValue);
}
}
}
四、读、写、通知
根据uuid,获取相应的特性,就可以进行读、写、通知操作:
/**
* 读取特性值
*
* @param gattCharacteristic 要读取的特性
*/
private boolean readCharacteristic(BluetoothGattCharacteristic gattCharacteristic) {
if (mBluetoothGatt != null) {
boolean readState = mBluetoothGatt.readCharacteristic(gattCharacteristic);
LogUtils.i("readCharacteristic " + readState);
return readState;
}
return false;
}
/**
* 写入特性值
*
* @param gattCharacteristic 要写入的特性
*/
private boolean writeCharacteristic(BluetoothGattCharacteristic gattCharacteristic, byte[] data) {
if (mBluetoothGatt != null) {
boolean writeState;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {//Android13及以上,适用此方法
writeState = mBluetoothGatt.writeCharacteristic(gattCharacteristic,
data, BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT)
== BluetoothStatusCodes.SUCCESS;
} else {//Android12及以下,适用此方法
writeState = mBluetoothGatt.writeCharacteristic(gattCharacteristic);
}
LogUtils.i("writeCharacteristic " + writeState);
return writeState;
}
return false;
}
/**
* 设置特性通知
*
* @param gattCharacteristic 需要获取通知的特性
* @param descriptorUuid 描述UUID
* @param enable true 获取特性变化通知 false 关闭通知
*/
private boolean setCharacteristicNotification(BluetoothGattCharacteristic gattCharacteristic, String descriptorUuid, boolean enable) {
if (mBluetoothGatt != null) {
boolean notifyCharacter = mBluetoothGatt.setCharacteristicNotification(gattCharacteristic, enable);
if (notifyCharacter) {
BluetoothGattDescriptor descriptor = gattCharacteristic.getDescriptor(UUID.fromString(descriptorUuid));
if (descriptor != null) {
boolean notifyState;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {//Android13及以上,适用此方法
notifyState = mBluetoothGatt.writeDescriptor(descriptor,
enable ? BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE : BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE)
== BluetoothStatusCodes.SUCCESS;
} else {//Android12及以下,适用此方法
if (enable) {
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
} else {
descriptor.setValue(BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE);
}
notifyState = mBluetoothGatt.writeDescriptor(descriptor);
}
LogUtils.i("setCharacteristicNotification notifyState " + notifyState);
return notifyState;
}
}
}
return false;
}
五、判断手机已连接的蓝牙设备
判断是否有已经连接的蓝牙设备,通过此方法可以看到手机连接了几个蓝牙设备,获取已连接蓝牙设备的信息:
/**
* 判断是否有已经连接的蓝牙设备
*/
public void isConnectedBleDevice() {
BluetoothManager manager = (BluetoothManager) mContext.getSystemService(BLUETOOTH_SERVICE);
if (manager != null) {
List connectedDevices = manager.getConnectedDevices(BluetoothProfile.GATT);
LogUtils.d("connectedDevices.size() " + connectedDevices.size());
for (BluetoothDevice bluetoothDevice : connectedDevices) {
LogUtils.d(bluetoothDevice.getAddress() + " " + bluetoothDevice.getName());
}
}
}
六、刷新缓存
蓝牙断开连接后,通过反射的方式刷新缓存:
/**
* 刷新缓存
*/
public void refreshDeviceCache() {
if (mBluetoothGatt != null) {
try {
Method localMethod = mBluetoothGatt.getClass().getMethod("refresh");
Boolean success = (Boolean) localMethod.invoke(mBluetoothGatt);
LogUtils.i("refreshDeviceCache, is success: " + success);
} catch (Exception e) {
LogUtils.e("exception occur while refreshing device: " + e.getMessage());
e.printStackTrace();
}
}
}