判断设备是否支持BLE
getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE);
开启蓝牙
BluetoothManager bluetoothManager =BluetoothManager)getSystemService(Context.BLUETOOTH_SERVICE);
bluetoothAdapter = bluetoothManager.getAdapter();
bluetoothAdapter.enable();
谷歌在4.3之后发布了低功耗蓝牙(BLE)的API,在安卓5.0之后又引入了新的API,原来的API已经被废弃。在新的系统里采用旧API开发的APP仍可使用,但采用新API开发的APP只能在LOLLIPOP即安卓5.0及其以后的版本使用。
扫描设备:
API<21
if (bluetoothAdapter.isEnabled()) {
bluetoothAdapter.startLeScan(leScanCallback);
} else {
Toast.makeText(this, "请开启蓝牙!", Toast.LENGTH_SHORT).show();
bluetoothAdapter.enable();
}
leScanCallback是开启扫描后的回调函数,所有扫描出的设备信息(设备名称name、设备mac地址 address 、设备信号强度rssi)全部包含在里面:
/**
* 搜索蓝牙 API 21以下版本
*/
private BluetoothAdapter.LeScanCallback leScanCallback = new BluetoothAdapter.LeScanCallback() {
@Override
public void onLeScan(final BluetoothDevice device, final int rssi, final byte[] scanRecord) {
runOnMainThread(new Runnable() {
@Override
public void run() {
BluetoothBean bluetoothBean = new BluetoothBean();
bluetoothBean.setName(device.getName());
bluetoothBean.setAddress(device.getAddress());
bluetoothBean.setRssi(rssi + "");
EventBus.getDefault().post(new ScanEvent(bluetoothBean));
}
});
}
};
当扫描到对应设备后可使用bluetoothAdapter.stopLeScan()方法停止搜索。
API>=21
if(bluetoothAdapter.isEnabled()) {
bluetoothLeScanner=bluetoothAdapter.getBluetoothLeScanner();
bluetoothLeScanner.startScan(scanCallback);
}else{
Toast.makeText(this,"请开启蓝牙!", Toast.LENGTH_SHORT).show();
bluetoothAdapter.enable();
}
scanCallback同leScanCallback
/**
* 搜索蓝牙 API 21(包含)以上版本
*/
private ScanCallback scanCallback = new ScanCallback() {
@Override
public void onScanResult(int callbackType, final ScanResult result) {
super.onScanResult(callbackType, result);
runOnMainThread(new Runnable() {
@Override
public void run() {
BluetoothBean bluetoothBean = new BluetoothBean();
bluetoothBean.setName(result.getDevice().getName());
bluetoothBean.setAddress(result.getDevice().getAddress());
bluetoothBean.setRssi(result.getRssi() + "");
EventBus.getDefault().post(new ScanEvent(bluetoothBean));
}
});
}
@Override
public void onBatchScanResults(List results) {
super.onBatchScanResults(results);
}
@Override
public void onScanFailed(int errorCode) {
super.onScanFailed(errorCode);
}
};
其中onBatchScanResults为批量搜索结果,
当扫描到对应设备后可使用bluetoothLeScanner.stopScan()方法停止搜索。
使用 bluetoothAdapter.getRemoteDevice()方法获取BluetoothDevice,其中的address参数为需要连接的设备的MAC地址,该值在扫描回调中可以获取到 ,然后调用BluetoothDevice 的connectGatt方法连接设备:
private boolean connectDevice(String address) {
if (bluetoothAdapter == null || address == null) {
return false;
}
final BluetoothDevice device = bluetoothAdapter.getRemoteDevice(address);
if (device == null) {
return false;
}
if (bluetoothGatt != null) {
bluetoothGatt.close();
}
bluetoothGatt = device.connectGatt(this, true, gattCallback);
return true;
}
其中gattCallback为设备连接回调,获取连接状态、读写操作均在此回调方法中进行。
在BluetoothGattCallback回调中,onConnectionStateChange为设备连接状态的回调方法,当设备开始连接、连接成功、断开连接中、断开连接后都会调用次方法:
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
if (newState == BluetoothProfile.STATE_CONNECTED) {
Log.i("info", "bluetooth is connected");
runOnMainThread(new Runnable() {
@Override
public void run() {
EventBus.getDefault().post(new ConnectSuccessEvent("ConnectSuccess"));
}
});
bluetoothGatt.discoverServices();
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
Log.i("info", "bluetooth is disconnected");
runOnMainThread(new Runnable() {
@Override
public void run() {
EventBus.getDefault().post(new DisConnectedEvent("DisConnected"));
}
});
}
}
当设备连接成功后,调用discoveryServices()发现服务,随后会进入onServicesDiscovered方法中,不调用则无法进入onServicesDiscovered方法,将无法获取到BluetoothGattService。
通过 bluetoothGatt.getServices()该方法可以获取到连接设备的所有服务(BluetoothGattService)的集合,通过遍历该集合可以获取到对应服务的特征BluetoothGattCharacteristic。
通过bluetoothGattCharacteristic.getProperties()可以获取可以获取当前特征的属性,该返回值为int类型:
@Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
List supportedGattServices = bluetoothGatt.getServices();
for (BluetoothGattService supportedGattService : supportedGattServices) {
for (BluetoothGattCharacteristic bluetoothGattCharacteristic : supportedGattService.getCharacteristics()) {
int properties = bluetoothGattCharacteristic.getProperties();
if (BluetoothGattCharacteristic.PROPERTY_NOTIFY == properties) {
//具备通知属性
UUID characteristicUuid = bluetoothGattCharacteristic.getUuid();
UUID gattServiceUuid = supportedGattService.getUuid();
}
}
}
}
当该值为BluetoothGattCharacteristic.PROPERTY_NOTIFY 则说明该特征具备通知属性。
当该值为BluetoothGattCharacteristic.PROPERTY_WRITE 则说明该值具备写入属性。
当该值为BluetoothGattCharacteristic.PROPERTY_READ 则说明该值具备读取属性。
此三种属性较为常用,当获取当对应的属性时,将serviceuuid和characteristicuuid保存起来即可。
例如当我们连接的蓝牙设备类似超市扫码枪,需要将扫描的条码传输到手机上时,此时则需要使用BluetoothGattCharacteristic特征的通知属性:
@Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
BluetoothGattService service = bluetoothGatt.getService(UUID.fromString(UUID_SERVICE));
BluetoothGattCharacteristic characteristic = service.getCharacteristic(UUID.fromString(UUID_NOTIFY));
//收到蓝牙模块的数据后会触发onCharacteristicChanged方法
bluetoothGatt.setCharacteristicNotification(characteristic, true);
}
当收到蓝牙模块的数据后会触发onCharacteristicChanged方法,在onCharacteristicChanged方法中则可以获取到扫码枪返回的数据:
@Override
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
final byte[] data = characteristic.getValue();
Log.e("info", "读取成功" + new String(data));
runOnMainThread(new Runnable() {
@Override
public void run() {
EventBus.getDefault().post(new BluetoothScanResultEvent(new String(data)));
}
});
}
该返回数据可能是原样数据,也可能返回的是16进制数据,具体根据硬件供应商的标准转换。
需要往设备里面写入数据时,将BluetoothGattCharacteristic换成具有写入属性BluetoothGattCharacteristic的,写入数据即可:
//设置数据内容
characteristic.setValue("send data->");
//往蓝牙模块写入数据
bluetoothGatt.writeCharacteristic(characteristic);
写入成功后会调用onCharacteristicWrite方法。
最后,附上该Demo的传送门:https://github.com/yfwang0810/Bluetooth
如有不足之处,欢迎大佬们指点一二。