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的主要内容,如果未能解决你的问题,请参考以下文章

Android 低功耗蓝牙(Ble) 开发总结

Qt低功耗蓝牙系列三(低功耗蓝牙客户端的程序设计纯Android代码)

Qt低功耗蓝牙系列三(低功耗蓝牙客户端的程序设计纯Android代码)

Android 低功耗蓝牙 (BLE) 环回

Android 低功耗Ble 蓝牙4.0多连接 开源框架

Android低功耗蓝牙BLE