Android低功耗蓝牙BLE
Posted 一杯清泉
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android低功耗蓝牙BLE相关的知识,希望对你有一定的参考价值。
低功耗蓝牙BLE与传统的蓝牙相比最大的优势是功耗降低90%,同时传输距离增大(超过100米)、安全和稳定性提高(支持AES加密和CRC验证),允许android应用程序与具有更严格电源要求的BLE设备进行通信,如接近传感器、心率传感器等低功耗设备。但是BLE蓝牙一包数据最多20个字节,因此在Android系统下传输大量数据就不太合适,还的需要使用经典蓝牙。
一、蓝牙权限
1、申请权限
静态注册:
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
动态申请定位权限:
String[] p = new String[]{Manifest.permission.ACCESS_FINE_LOCATION};
ActivityCompat.requestPermissions(activity,p,1000);
如果您的目标是 Android 10,那么您需要 ACCESS_FINE_LOCATION 来扫描。ACCESS_COARSE_LOCATION 在 Android 10 中不再起作用。本次项目targetApi为29。
2、打开手机定位
Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
MainActivity a = (MainActivity) activity;
a.startActivityForResult(intent, OPEN_GPS_CODE)
注意:蓝牙的搜索、配对等等后续功能都需要开启权限,否则啥也获取不到。
二、获取蓝牙设备的RSSI
1、已经配对
BluetoothDevice remoteDevice = bluetoothAdapter.getRemoteDevice(deviceId);
remoteDevice.connectGatt(activity, false, new BluetoothGattCallback() {
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
super.onConnectionStateChange(gatt, status, newState);
handler.postDelayed(new Runnable() {
@Override
public void run() {
gatt.readRemoteRssi();
}
}, 1000);
}
@Override
public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {
super.onReadRemoteRssi(gatt, rssi, status);
LogUtils.d("onReadRemoteRssi:" + rssi);
}
});
2、未配对
public void getBLEDeviceRSSI(JsBLEBean bean) {
IntentFilter filter = new IntentFilter();
filter.addAction(BluetoothDevice.ACTION_FOUND);
activity.registerReceiver(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(BluetoothDevice.ACTION_FOUND)){
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
if (device.getAddress().equals(deviceId)){
short rssi = intent.getShortExtra(BluetoothDevice.EXTRA_RSSI, (short) 0);
//信号强度
LogUtils.d("device.getAddress():"+device.getAddress());
LogUtils.d("device.getAddress():"+rssi);
}
}
}
}, filter);
bluetoothAdapter.startDiscovery();
}
三、BLE蓝牙搜索
已知蓝牙的Mac地址:deviceId
//过滤条件
ArrayList<ScanFilter> scanFilterList = new ArrayList<>();
ScanFilter scanFilter = new ScanFilter.Builder()
.setDeviceAddress(deviceId)
.build();
scanFilterList.add(scanFilter);
//扫描设置。
ScanSettings scanSettings = new ScanSettings.Builder()
.setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
.setReportDelay(0)
.build();
//连接
BluetoothLeScanner bluetoothLeScanner = bluetoothAdapter.getBluetoothLeScanner();
BleScanning bleScanning = new BleScanning(callback);
bluetoothLeScanner.startScan(scanFilterList, scanSettings, new ScanCallback() {
@Override
public void onScanResult(int callbackType, ScanResult result) {
super.onScanResult(callbackType, result);
}
@Override
public void onBatchScanResults(List<ScanResult> results) {
super.onBatchScanResults(results);
}
@Override
public void onScanFailed(int errorCode) {
super.onScanFailed(errorCode);
}
});
四、BLE蓝牙连接
device.connectGatt(activity, false, callback);
参数2:是直接连接到远程设备(false)还是在远程设备可用时自动连接(true)。注意如果是直接连接使用false。
参数3:将接收异步回调的 GATT 回调处理程序。
1、已经配对了
Set<BluetoothDevice> pairedDevices = bluetoothAdapter.getBondedDevices();
if (pairedDevices.size() > 0) {
for (BluetoothDevice device : pairedDevices) {
String id = device.getAddress();
if (deviceId.equals(id)) {
device.connectGatt(activity, true, new BluetoothGattCallback() {
if (status == BluetoothGatt.GATT_SUCCESS) {
if (newState == BluetoothProfile.STATE_CONNECTED) {
// 已连接状态,表明连接成功
// 连接到蓝牙后查找可以读写的服务
ApplicationUtils.getMainHander().postDelayed(new Runnable() {
@Override
public void run() {
//延迟一秒,否则扫描失败,没有onServicesDiscovered回调
gatt.discoverServices();//扫描特征值
}
}, 1000);
} else if(newState == BluetoothProfile.STATE_DISCONNECTED) {
// 避免其他情况出现,不满足条件的都断开连接
close(gatt);
LogUtils.d("连接失败");
}
} else {
close(gatt);
LogUtils.d("连接失败");
}
}
}
//关闭资源,否则会出现BluetoothGatt status 133
public void close(BluetoothGatt gatt) {
if (gatt != null) {
ApplicationUtils.getMainHander().post(new Runnable() {
@Override
public void run() {
gatt.disconnect();
gatt.close();
}
});
}
}
蓝牙连接随时可能断开,建议监听状态,断开后重新连接即可。
2、没有配对
则执行上一步搜索BLE设备,然后配对,再执行上面的连接方法。
五、获取蓝牙设备所有服务
BluetoothDevice remoteDevice = bluetoothAdapter.getRemoteDevice(deviceId);
remoteDevice.connectGatt(activity, false, new BluetoothGattCallback() {
@Override
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
super.onCharacteristicChanged(gatt, characteristic);
LogUtils.d("onCharacteristicChanged");
}
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
super.onConnectionStateChange(gatt, status, newState);
LogUtils.d("onConnectionStateChange");
// 已连接状态,表明连接成功
if (newState == BluetoothProfile.STATE_CONNECTED) {
// 连接到蓝牙后查找可以读写的服务
handler.postDelayed(new Runnable() {
@Override
public void run() {
//延迟一秒,否则扫描失败,没有onServicesDiscovered回调
gatt.discoverServices();//扫描特征值
}
}, 1000);
return;
}
// 断开连接或未连接成功
if (newState == BluetoothProfile.STATE_DISCONNECTED) {
LogUtils.d("断开接连");
return;
}
// 避免其他情况出现,不满足条件的都断开连接
gatt.disconnect();
gatt.close();
}
@Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
super.onServicesDiscovered(gatt, status);
if (status == BluetoothGatt.GATT_SUCCESS) { //BLE服务发现成功
List<BluetoothGattService> services = gatt.getServices();
for (BluetoothGattService service : services) {
JsCreateGetBLEDeviceServicesBean.DataBean dataBean = new JsCreateGetBLEDeviceServicesBean.DataBean();
//服务的UUID
String uuid = service.getUuid().toString();
//是否是主服务
String isPrimary = service.getType() == BluetoothGattService.SERVICE_TYPE_PRIMARY;
}
}
}
});
六、获取蓝牙设备某个服务中所有特征值
BluetoothDevice remoteDevice = bluetoothAdapter.getRemoteDevice(deviceId);
remoteDevice.connectGatt(activity, false, new BluetoothGattCallback() {
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
super.onConnectionStateChange(gatt, status, newState);
LogUtils.d("onConnectionStateChange");
// 已连接状态,表明连接成功
if (newState == BluetoothProfile.STATE_CONNECTED) {
// 连接到蓝牙后查找可以读写的服务
handler.postDelayed(new Runnable() {
@Override
public void run() {
//延迟一秒,否则扫描失败,没有onServicesDiscovered回调
gatt.discoverServices();//扫描特征值
}
}, 1000);
return;
}
// 断开连接或未连接成功
if (newState == BluetoothProfile.STATE_DISCONNECTED) {
return;
}
// 避免其他情况出现,不满足条件的都断开连接
gatt.disconnect();
gatt.close();
}
@Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
super.onServicesDiscovered(gatt, status);
gatt.requestMtu(mtu);
LogUtils.d("onServicesDiscovered");
if (status == BluetoothGatt.GATT_SUCCESS) { //BLE服务发现成功
List<BluetoothGattService> services = gatt.getServices();
for (BluetoothGattService service : services) {
if (service.getUuid().toString().equals(serviceId)) {
BluetoothGattService gattService = gatt.getService(UUID.fromString(serviceId));
if (gattService != null) {
//设备的特征值列表
List<BluetoothGattCharacteristic> characteristics = gattService.getCharacteristics();
for (BluetoothGattCharacteristic characteristic : characteristics) {
LogUtils.d("找到对应可读写特征");
String uuid = characteristic.getUuid().toString();
String properties;
switch (characteristic.getProperties()) {
case BluetoothGattCharacteristic.PROPERTY_READ:
properties = "read";
break;
case BluetoothGattCharacteristic.PROPERTY_WRITE:
properties = "write";
break;
case BluetoothGattCharacteristic.PROPERTY_NOTIFY:
properties = "notify";
break;
case BluetoothGattCharacteristic.PROPERTY_INDICATE:
properties = "indicate";
break;
default:
break;
}
}
}
}
}
}
}
});
七、接收通知消息,订阅特征值
BluetoothDevice remoteDevice = bluetoothAdapter.getRemoteDevice(deviceId);
remoteDevice.connectGatt(activity, false, new BluetoothGattCallback() {
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
super.onConnectionStateChange(gatt, status, newState);
LogUtils.d("onConnectionStateChange");
// 已连接状态,表明连接成功
if (newState == BluetoothProfile.STATE_CONNECTED) {
// 连接到蓝牙后查找可以读写的服务
handler.postDelayed(new Runnable() {
@Override
public void run() {
//延迟一秒,否则扫描失败,没有onServicesDiscovered回调
gatt.discoverServices();//扫描特征值
}
}, 1000);
return;
}
// 断开连接或未连接成功
if (newState == BluetoothProfile.STATE_DISCONNECTED) {
return;
}
// 避免其他情况出现,不满足条件的都断开连接
gatt.disconnect();
gatt.close();
}
@Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
super.onServicesDiscovered(gatt, status);
if (status == BluetoothGatt.GATT_SUCCESS) { //BLE服务发现成功
BluetoothGattService gattService = gatt.getService(UUID.fromString(serviceId));
if (gattService != null) {
//设备的特征值列表
List<BluetoothGattCharacteristic> characteristics = gattService.getCharacteristics();
for (BluetoothGattCharacteristic characteristic : characteristics) {
if (characteristic.getUuid().toString().equals(characteristicId)) {
//启动特征值通知
gatt.setCharacteristicNotification(characteristic, true);
byte[] value = state ? BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE : BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE;
BluetoothGattDescriptor descriptor = characteristic.getDescriptor(UUID.fromString(characteristicId));
if (descriptor == null) {
descriptor = new BluetoothGattDescriptor(UUID.fromString(characteristicId),
BluetoothGattDescriptor.PERMISSION_WRITE);
}
descriptor.setValue(value);
gatt.writeDescriptor(descriptor);
}
}
}
}
}
@Override
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
super.onCharacteristicChanged(gatt, characteristic);
//当我们决定用通知的方式获取外设特征值的时候,每当特征值发生变化,程序就会回调到此处。
//特征值最新的值
byte[] value = characteristic.getValue();
}
});
八、写入低功耗蓝牙设备特征值二进制数据
String deviceId = data.deviceId;
String characteristicId = characteristicId;
String serviceId = data.serviceId;
byte[] bytes = data.value;
BluetoothDevice remoteDevice = bluetoothAdapter.getRemoteDevice(deviceId);
remoteDevice.connectGatt(activity, false, new BluetoothGattCallback() {
@Override
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
super.onCharacteristicChanged(gatt, characteristic);
//特征值最新的值
byte[] value = characteristic.getValue();
}
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
super.onConnectionStateChange(gatt, status, newState);
LogUtils.d("onConnectionStateChange");
// 已连接状态,表明连接成功
if (newState == BluetoothProfile.STATE_CONNECTED) {
LogUtils.d("连接成功");
// 连接到蓝牙后查找可以读写的服务
handler.postDelayed(new Runnable() {
@Override
public void run() {
//延迟一秒,否则扫描失败,没有onServicesDiscovered回调
gatt.discoverServices();//扫描特征值
}
}, 1000);
return;
}
// 断开连接或未连接成功
if (newState == BluetoothProfile.STATE_DISCONNECTED) {
LogUtils.d("断开接连");
return;
}
// 避免其他情况出现,不满足条件的都断开连接
gatt.disconnect();
gatt.close();
}
@Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
super.onServicesDiscovered(gatt, status);
gatt.requestMtu(mtu);
LogUtils.d("onServicesDiscovered");
if (status == BluetoothGatt.GATT_SUCCESS) { //BLE服务发现成功
BluetoothGattService gattService = gatt.getService(UUID.fromString(serviceId));
if (gattService != null) {
BluetoothGattCharacteristic characteristic = gattService.getCharacteristic(
UUID.fromString(characteristicId));
if (characteristic != null) {
characteristic.setValue(bytes);
gatt.writeCharacteristic(characteristic);
LogUtils.d("writeData:写了一次数据!");
}
}
}
}
@Override
public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
super.onCharacteristicWrite(gatt, characteristic, status);
if (characteristic.getUuid().toString().equals(serviceId)) {
byte[] value = characteristic.getValue();
}
});
九、读取低功耗蓝牙设备特征值二进制数据
String deviceId = data.deviceId;
String characteristicId = data.characteristicId;
String serviceId = data.serviceId;
byte[] bytes = data.value;
BluetoothDevice remoteDevice = bluetoothAdapter.getRemoteDevice(deviceId);
remoteDevice.connectGatt(activity, false, new BluetoothGattCallback() {
@Override
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
super.onCharacteristicChanged(gatt, characteristic);
//特征值最新的值
byte[] value = characteristic.getValue();
}
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
super.onConnectionStateChange(gatt, status, newState);
LogUtils.d("onConnectionStateChange");
// 已连接状态,表明连接成功
if (newState == BluetoothProfile.STATE_CONNECTED) {
LogUtils.d("连接成功");
// 连接到蓝牙后查找可以读写的服务
handler.postDelayed(new Runnable() {
@Override
public void run() {
//延迟一秒,否则扫描失败,没有onServicesDiscovered回调
gatt.discoverServices();//扫描特征值
}
}, 1000);
return;
}
// 断开连接或未连接成功
if (newState == BluetoothProfile.STATE_DISCONNECTED) {
LogUtils.d("断开接连");
return;
}
// 避免其他情况出现,不满足条件的都断开连接
gatt.disconnect();
gatt.close();
}
@Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
super.onServicesDiscovered(gatt, status);
gatt.requestMtu(mtu);
LogUtils.d("onServicesDiscovered");
if (status == BluetoothGatt.GATT_SUCCESS) { //BLE服务发现成功
BluetoothGattService gattService = gatt.getService(UUID.fromString(serviceId));
if (gattService != null) {
BluetoothGattCharacteristic characteristic = gattService.getCharacteristic(
UUID.fromString(characteristicId));
if (characteristic != null) {
gatt.readCharacteristic(characteristic);
LogUtils.d("readData:读了一次数据!");
}
}
}
}
@Override
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
super.onCharacteristicRead(gatt, characteristic, status);
if (characteristic.getUuid().toString().equals(serviceId)) {
byte[] value = characteristic.getValue();
}
}
});
十、设置蓝牙最大传输单元
最大传输单元(22,512) 区间内,单位 bytes。
BluetoothDevice remoteDevice = bluetoothAdapter.getRemoteDevice(deviceId);
remoteDevice.connectGatt(activity, false, new BluetoothGattCallback() {
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
super.onConnectionStateChange(gatt, status, newState);
// 已连接状态,表明连接成功
if (newState == BluetoothProfile.STATE_CONNECTED) {
// 连接到蓝牙后查找可以读写的服务
handler.postDelayed(new Runnable() {
@Override
public void run() {
//延迟一秒,否则扫描失败,没有onServicesDiscovered回调
gatt.discoverServices();//扫描特征值
}
}, 1000);
return;
}
// 断开连接或未连接成功
if (newState == BluetoothProfile.STATE_DISCONNECTED) {
return;
}
// 避免其他情况出现,不满足条件的都断开连接
gatt.disconnect();
gatt.close();
}
@Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
super.onServicesDiscovered(gatt, status);
//在这设置
gatt.requestMtu(mtu);
}
});
以上是关于Android低功耗蓝牙BLE的主要内容,如果未能解决你的问题,请参考以下文章
Qt低功耗蓝牙系列三(低功耗蓝牙客户端的程序设计纯Android代码)