近日,接到需要用到蓝牙解锁硬件设备的新需求,开发过程中呢也遇到许多硬件的坑,开发协议文档较简单,几句话就完了,第一次搞得我自己一脸懵逼,本来一两个小时就能写完并测试完成的过程用了两三天。哎!默默地回到这里疯狂输出,记录下一些不必要的坑。下面开始我的蓝牙开发吧!走了以前的老路,就是拿到蓝牙需求就叫我先根据设计好的密钥配对连接,花了点时间,然后靠广播接收回调各种信息。setPin()方法也一直不成功。但是时间实在是有点紧了,耗不住了,果断放弃老方法了,开始尝试ble 4.0的方式方法。几步就ok了;
第一部,初始化蓝牙
BluetoothAdapter mBluetoothAdapter;
private void getBlueToothAdapter() {
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (mBluetoothAdapter == null) {
MyToast.showShort(this, "设备不支持蓝牙,已为您切换到网络模式");
operationType = 2;
rightTxt.setText("蓝牙模式");
return;
}
if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
MyToast.showShort(this, "设备不支持蓝牙4.0");
return;
}
openBlueTooth();
}
第二步,开启蓝牙
public static int BL_REQUESTCODE = 1;
private void openBlueTooth() {
if (mBluetoothAdapter.isEnabled()) {
MyToast.showShort(this, "蓝牙已打开");
scanBlueTooth();
} else {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);//这里是打开有提示是否开启蓝牙的方式
startActivityForResult(enableBtIntent, BL_REQUESTCODE);
}
}
//关闭蓝牙
private void closeBlueTooth() {
mBluetoothAdapter.disable();
}
第三步,蓝牙扫描搜索
private void scanBlueTooth() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
//扫描需要一个回调。
mBluetoothAdapter.startLeScan(scanCallBack);
}
//搜索后15秒关闭蓝牙扫描
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
mBluetoothAdapter.stopLeScan(scanCallBack);//停止扫描
}
}
}, 15000);
}
//蓝牙扫描搜索回调
public BluetoothAdapter.LeScanCallback scanCallBack = new BluetoothAdapter.LeScanCallback() {
@Override
public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) {
if (device.getName().equals("蓝牙的名字")) {//这里是根据蓝牙的名字筛选出想要连接的蓝牙,根据mac地址亦可以
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
//停止搜索蓝牙并连接蓝牙
mBluetoothAdapter.stopLeScan(scanCallBack);
connectBlueTooth(device);//连接设备
}
}
}
};
第四步,连接蓝牙设备
BluetoothGattCharacteristic writeBluetoothCharacteristic;
BluetoothGatt writeBluetoothGatt;
private void connectBlueTooth(BluetoothDevice device) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
//参数1:上下文。//参数2:是否自动连接(当设备可以用时)//参数3:连接回调。
mBluetoothAdapter.stopLeScan(scanCallBack);
device.connectGatt(this, true, mGattCallback);
}
}
//蓝牙连接回调
private BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
super.onConnectionStateChange(gatt, status, newState);
if (newState == BluetoothProfile.STATE_CONNECTED) {
//连接成功
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
//开始发现设备的服务
gatt.discoverServices();
}
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
//连接断开
}
}
@Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
super.onServicesDiscovered(gatt, status);
boolean success = false;
//当服务发现之后回调这里
if (status == BluetoothGatt.GATT_SUCCESS) {
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR2) {
//根据服务UUID连接服务
BluetoothGattService service = gatt.getService(UUID.fromString("00001000-0000-1000-8000-00805f9b34fb"));
//根据特征UUID注册特征
BluetoothGattCharacteristic characteristic_write = findNotifyCharacteristic(service, UUID.fromString("00001001-0000-1000-8000-00805f9b34fb"));
BluetoothGattCharacteristic characteristic_notifi = findNotifyCharacteristic(service, UUID.fromString("00001002-0000-1000-8000-00805f9b34fb"));
if (characteristic_notifi != null) {
success = gatt.setCharacteristicNotification(characteristic_notifi, true);
if (success) {
characteristic_write.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT);
for (BluetoothGattDescriptor dp : characteristic_write.getDescriptors()) {
if (dp != null) {
if ((characteristic_write.getProperties() & BluetoothGattCharacteristic.PROPERTY_NOTIFY) != 0) {
dp.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
} else if ((characteristic_write.getProperties() & BluetoothGattCharacteristic.PROPERTY_INDICATE) != 0) {
dp.setValue(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE);
}
gatt.writeDescriptor(dp);//这里触发发送指令的回调
}
}
}
}
}
}
}
@Override
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
super.onCharacteristicRead(gatt, characteristic, status);
//调用读取READ通道后返回的数据回调
if (status == BluetoothGatt.GATT_SUCCESS) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
// Log.e("读取蓝牙数据", "" + BlueToothUtils.bytesToHexFun2(BlueToothUtils.JM3(characteristic.getValue())));
}
}
}
@Override
public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
super.onCharacteristicWrite(gatt, characteristic, status);
if (status == BluetoothGatt.GATT_SUCCESS) {//写入成功
} else if (status == BluetoothGatt.GATT_FAILURE) {//写入失败
} else if (status == BluetoothGatt.GATT_WRITE_NOT_PERMITTED) {//没权限
}
}
@Override
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
super.onCharacteristicChanged(gatt, characteristic);
//蓝牙推送过来的数据
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
// Log.e("蓝牙推送过来的数据", "" + BlueToothUtils.bytesToHexFun2(BlueToothUtils.JM3(characteristic.getValue())));
}
}
@Override
public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
super.onDescriptorWrite(gatt, descriptor, status);
writeBluetoothGatt = gatt;
BluetoothGattService writeService = null;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR2) {
writeService = gatt.getService(UUID.fromString("00001000-0000-1000-8000-00805f9b34fb"));
if (writeService == null) {
return;
}
writeBluetoothCharacteristic = writeService.getCharacteristic(UUID.fromString("00001001-0000-1000-8000-00805f9b34fb"));
if (writeBluetoothCharacteristic == null) {
return;
}
bluetooth_sendMessage(pwd, false);
}
}
};
private BluetoothGattCharacteristic findNotifyCharacteristic(BluetoothGattService service, UUID characteristicUUID) {//此方法是在没有收到蓝牙的通知回调加的,最后才确定了是硬件那边本来就没给我回调信息,当然加入此方法也不会有问题
BluetoothGattCharacteristic characteristic = null;
List<BluetoothGattCharacteristic> characteristics = null;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR2) {
characteristics = service.getCharacteristics();
for (BluetoothGattCharacteristic c : characteristics) {
if ((c.getProperties() & BluetoothGattCharacteristic.PROPERTY_NOTIFY) != 0
&& characteristicUUID.equals(c.getUuid())) {
characteristic = c;
break;
}
}
if (characteristic != null)
return characteristic;
for (BluetoothGattCharacteristic c : characteristics) {
if ((c.getProperties() & BluetoothGattCharacteristic.PROPERTY_INDICATE) != 0
&& characteristicUUID.equals(c.getUuid())) {
characteristic = c;
break;
}
}
}
return characteristic;
}
//蓝牙发送指令
private void bluetooth_sendMessage(byte[] message, boolean flag) {
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR2) {
if (writeBluetoothCharacteristic == null) {
return;
}
if (flag) {
message = BlueToothUtils.Agreement_Encryption(message, message.length);
}
writeBluetoothCharacteristic.setValue(message);
//上面的buffer数组中装的就是指令,多长? 每一位上面的数字代表什么意思在协议中查看!
writeBluetoothGatt.writeCharacteristic(writeBluetoothCharacteristic);//向设备写入指令。
}
}
最后加上权限。这里需要自己去动态申请6.0的定位权限
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
<uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/>