一、准备
权限
<!--蓝牙权限和蓝牙设备的扫描设置权限-->
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<!--扫描蓝牙需要位置权限-->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
二、扫描附近的设备
我们先判断一下有没有位置权限,如果没有,是搜不到附近的设备的。这里我们要借助Handler去实现,因为蓝牙搜索有一定的时间,不可能让手机一直处于搜索蓝牙的阶段,一般是10s。
if (mBleHandler == null) {
mBleHandler = new Handler();
}
mSppAdapter= BluetoothAdapter.getDefaultAdapter();//ble蓝牙
mBleHandler.postDelayed(new Runnable() {
@Override
public void run() {
//10s后扫描结束
mSppAdapter.stopLeScan(leScanCallback);
mBleHandler.removeCallbacksAndMessages(null);//handler close!!!
}
}, 10000);
mSppAdapter.startLeScan(leScanCallback);
扫描到的结果会通过leScanCallback这个接口回调。
private BluetoothAdapter.LeScanCallback leScanCallback = new BluetoothAdapter.LeScanCallback() {
@Override
public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) {
runOnUiThread(new Runnable() {
@Override
public void run() {
String address = device.getAddress();
String name = device.getName();
});
}
};
这里我使用了runOnUiThread,这个类似于handler的机制,可以在其中更新UI。(向用户展示搜到的设备)
三、连接
对于连接这一块的内容,笔者建议用一个Service去维护和设备的连接。
final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
if (device == null) {
return false;
}
device.connectGatt(this, false, mGattCallback);
private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
连接状态改变的回调
if (newState == BluetoothProfile.STATE_CONNECTED) {
//Connected to GATT server.
//连接成功之后,我们应该去寻找服务.
try {
Thread.sleep(1000);
mBluetoothGatt.discoverServices();
} catch (InterruptedException e) {
e.printStackTrace();
}
//连接成功,发送消息
mHandler.sendEmptyMessage(STATE_CONNECTED);
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
//断连发送消息
mHandler.sendEmptyMessage(STATE_DISCONNECTED);
if (mBluetoothGatt != null) {
mBluetoothGatt.close();
mBluetoothGatt = null;
}
}
}
@Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
//发现服务后,我们就要查找读写的Characteristic
if (status == BluetoothGatt.GATT_SUCCESS) {
isServiceDiscover = true;
BluetoothGattService serviceRead;
BluetoothGattService serviceWrite;
serviceRead = gatt.getService(UUID.fromString("49535343-fe7d-4ae5-8fa9-9fafd205e455"));
serviceWrite = gatt.getService(UUID.fromString("49535343-fe7d-4ae5-8fa9-9fafd205e4555"));
if (serviceRead != null) {
mNotifyCharacteristic = serviceRead.getCharacteristic(UUID.fromString("49535343-1e4d-4bd9-ba61-23c647249616"));
}
if (serviceWrite != null) {
mWriteCharacteristic = serviceWrite.getCharacteristic(UUID.fromString("49535343-8841-43f4-a8d4-ecbe34729bb3"));
}
if (mNotifyCharacteristic != null) {
//设置可以接收通知,后面介绍
setCharacteristicNotification(characteristic, ture);
}
} else {
//服务连接失败
}
}
// 如果读取值成功之后的回调
@Override
public void onCharacteristicRead(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic,
int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
//收到设备notify值 (设备上报值)
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
}
}
//也就是readDescriptor成功后
@Override
public void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
}
}
//收到设备notify值 (设备上报值),根据 characteristic.getUUID()来判断发送者
@Override
public void onCharacteristicChanged(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic) {
Timber.i("onCharacteristicChanged");
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
}
//发送命令给设备成功之后,会回调这里
@Override
public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
//write成功(发送值成功)
msgSendLoopHandler.notifyObj();
}
}
//调用打开通知成功后会回调这里writeDescriptor
//也就是writeDescriptor成功后
@Override
public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
msgSendLoopHandler.notifyObj();
}
}
@Override
public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {
//读取Rssi值
}
};
msgSendLoopHandler.notifyObj();这里先不用管,文章后面介绍。
四、读写
首先我们来说读。第一部就是打开开关,就是上面说的onDescriptorWrite这里的回调,我们要怎么做呢,看下面就知道了。
public void setCharacteristicNotification(BluetoothGattCharacteristic characteristic,
boolean enabled) {
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
return;
}
boolean b1 = mBluetoothGatt.setCharacteristicNotification(characteristic, enabled);
if (UUID_BLE_SPP_NOTIFY.equals(characteristic.getUuid()) {
BluetoothGattDescriptor descriptor = characteristic.getDescriptor(
UUID.fromString("00002902-0000-1000-8000-00805f9b34fb");
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
sendSuccess = bluetoothLeService.mBluetoothGatt.writeDescriptor(descriptor);
}
}
这般设置之后,便可以在onCharacteristicChanged中收到设备上报的数据了。
下面我们来说说写数据:
byte[] tempBytes = new byte[sendSize];
mWriteCharacteristic.setValue(tempBytes);
mBluetoothGatt.writeCharacteristic(mWriteCharacteristic);
这里要注意,确保ServiceDiscover。mWriteCharacteristic是在找到服务后的地方获取的。(上面有介绍onServicesDiscovered
中)