Android蓝牙开发——BLE(低功耗蓝牙)(附完整Demo)
Posted 摸爬滚打的程序媛
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android蓝牙开发——BLE(低功耗蓝牙)(附完整Demo)相关的知识,希望对你有一定的参考价值。
目录
1、2020/12/29 :修改 setupService()中错误
2、2021/05/14 :更新连接方法(解决部分蓝牙设备连接失败的问题)
前言
之前的几篇文章,主要介绍了经典蓝牙开发相关的知识,今天我们就来看看低功耗蓝牙的开发。如果小伙伴们对之前的文章感兴趣兴趣,也可以看看,欢迎提出不足或者建议。
【Android】蓝牙开发——经典蓝牙配对介绍(通过手机系统蓝牙演示)
【Android】蓝牙开发—— 经典蓝牙配对介绍(Java代码实现演示)附Demo源码
一、相关概念介绍
BLE,全称 Bluetooth Low Energy,即低功耗蓝牙。BLE关键术语和概念,可以查看官网介绍:
https://developer.android.google.cn/guide/topics/connectivity/bluetooth-le
首先,我们需要知道,BLE设备有以下几个方面的东西:
1、一个BLE设备包含多个服务,这些服务通过UUID来区分。
2、一个服务包含1个或多个特征,这些特征也是通过UUID来区分。
3、一个特征包含一个Value和多个描述符,一个描述符包含一个Value,
其次,我们来看一看android中BLE相关的对象:
1、BluetoothDevice :蓝牙设备
2、BluetoothGatt:建立的连接
3、BluetoothGattCallback:连接回调
3、BluetoothGattService:服务
4、BluetoothGattCharacteristic:服务的特征
5、BluetoothGattDescriptor:特征的描述
了解了这些之后,我们开始进入BLE开发阶段。
二、实战开发
注意:BLE是在Android 4.3(API 18)以后引入的,所以要进行BLE开发,必须在Android 4.3以上版本的机子上。
1、添加相关权限
(1)蓝牙权限
<!-- 应用使用蓝牙的权限 --> <uses-permission android:name="android.permission.BLUETOOTH"/> <!--启动设备发现或操作蓝牙设置的权限--> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
(2)位置权限(BLE与经典蓝牙相比,还需要位置权限,如果没有,有的机型是扫描不到设备的,注意Android6.0以后还需要动态申请位置权限)
<!--位置权限--> <!--Android 10以上系统,需要ACCESS_FINE_LOCATION--> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/> <!--Android 9以及以下系统,需要ACCESS_FINE_LOCATION--> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
2、使用蓝牙之前,首先要检查当前手机是否支持BLE蓝牙。如果支持BLE蓝牙,检查手机蓝牙是否已开启。如果没有开启,则需要先打开蓝牙。打开手机蓝牙,有两种方式,一种是直接enable()打开,另外一种是提示用户打开,推荐第二种方式。
/** * 检测手机是否支持4.0蓝牙 * @param context 上下文 * @return true--支持4.0 false--不支持4.0 */ private boolean checkBle(Context context) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) //API 18 Android 4.3 bluetoothManager = (BluetoothManager) context.getSystemService(Context.BLUETOOTH_SERVICE); if(bluetoothManager == null) return false; bluetooth4Adapter = bluetoothManager.getAdapter(); //BLUETOOTH权限 if(bluetooth4Adapter == null) return false; else Log.d(TAG,"该设备支持蓝牙4.0"); return true; else return false;
/** * 获取蓝牙状态 */ public boolean isEnable() if(bluetooth4Adapter == null) return false; return bluetooth4Adapter.isEnabled(); /** * 打开蓝牙 * @param isFast true 直接打开蓝牙 false 提示用户打开 */ public void openBluetooth(Context context,boolean isFast) if(!isEnable()) if(isFast) Log.d(TAG,"直接打开手机蓝牙"); bluetooth4Adapter.enable(); //BLUETOOTH_ADMIN权限 else Log.d(TAG,"提示用户去打开手机蓝牙"); Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); context.startActivity(enableBtIntent); else Log.d(TAG,"手机蓝牙状态已开");
3、系统蓝牙已打开,则可以开启扫描设备。需要注意的是,扫描设备是耗时的操作,一旦扫描结束,就要及时停止扫描。
扫描设备 /// //扫描设备回调 @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2) private BluetoothAdapter.LeScanCallback leScanCallback = new BluetoothAdapter.LeScanCallback() @Override public void onLeScan(BluetoothDevice bluetoothDevice, int rssi, byte[] bytes) //在onLeScan()回调中尽量做少的操作,可以将扫描到的设备扔到另一个线程中处理 if(bluetoothDevice == null) return; if(bluetoothDevice.getName() != null) Log.d(TAG,bluetoothDevice.getName() + "-->" + bluetoothDevice.getAddress()); else Log.d(TAG,"null" + "-->" + bluetoothDevice.getAddress()); BLEDevice bleDevice = new BLEDevice(bluetoothDevice,rssi); if(onDeviceSearchListener != null) onDeviceSearchListener.onDeviceFound(bleDevice); //扫描到设备回调 ; /** * 设置时间段 扫描设备 * @param onDeviceSearchListener 设备扫描监听 * @param scanTime 扫描时间 */ public void startDiscoveryDevice(OnDeviceSearchListener onDeviceSearchListener,long scanTime) if(bluetooth4Adapter == null) Log.e(TAG,"startDiscoveryDevice-->bluetooth4Adapter == null"); return; this.onDeviceSearchListener = onDeviceSearchListener; if(onDeviceSearchListener != null) onDeviceSearchListener.onDiscoveryStart(); //开始扫描回调 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) Log.d(TAG,"开始扫描设备"); bluetooth4Adapter.startLeScan(leScanCallback); else return; //设定最长扫描时间 mHandler.postDelayed(stopScanRunnable,scanTime); private Runnable stopScanRunnable = new Runnable() @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2) @Override public void run() if(onDeviceSearchListener != null) onDeviceSearchListener.onDiscoveryOutTime(); //扫描超时回调 //scanTime之后还没有扫描到设备,就停止扫描。 stopDiscoveryDevice(); ;
4、扫描到目标设备之后,开始建立连接,这里注意,连接之前一定要关闭扫描,否则会影响连接。BLE与经典蓝牙不同,经典蓝牙一旦建立连接,就可以进行数据通讯,而BLE建立连接之后,还需要发现系统服务,获取特定服务及读写特征。
(1)建立连接 & 发现系统服务
/ 执行连接 // //连接/通讯结果回调 @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2) private BluetoothGattCallback bluetoothGattCallback = new BluetoothGattCallback() @Override public void onPhyUpdate(BluetoothGatt gatt, int txPhy, int rxPhy, int status) super.onPhyUpdate(gatt, txPhy, rxPhy, status); @Override public void onPhyRead(BluetoothGatt gatt, int txPhy, int rxPhy, int status) super.onPhyRead(gatt, txPhy, rxPhy, status); //连接状态回调-连接成功/断开连接 @Override public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) super.onConnectionStateChange(gatt, status, newState); Log.d(TAG,"status:" + status); Log.d(TAG,"newState:" + newState); switch(status) case BluetoothGatt.GATT_SUCCESS: Log.w(TAG,"BluetoothGatt.GATT_SUCCESS"); break; case BluetoothGatt.GATT_FAILURE: Log.w(TAG,"BluetoothGatt.GATT_FAILURE"); break; case BluetoothGatt.GATT_CONNECTION_CONGESTED: Log.w(TAG,"BluetoothGatt.GATT_CONNECTION_CONGESTED"); break; case BluetoothGatt.GATT_INSUFFICIENT_AUTHENTICATION: Log.w(TAG,"BluetoothGatt.GATT_INSUFFICIENT_AUTHENTICATION"); break; case BluetoothGatt.GATT_INSUFFICIENT_ENCRYPTION: Log.w(TAG,"BluetoothGatt.GATT_INSUFFICIENT_ENCRYPTION"); break; case BluetoothGatt.GATT_INVALID_OFFSET: Log.w(TAG,"BluetoothGatt.GATT_INVALID_OFFSET"); break; case BluetoothGatt.GATT_READ_NOT_PERMITTED: Log.w(TAG,"BluetoothGatt.GATT_READ_NOT_PERMITTED"); break; case BluetoothGatt.GATT_REQUEST_NOT_SUPPORTED: Log.w(TAG,"BluetoothGatt.GATT_REQUEST_NOT_SUPPORTED"); break; BluetoothDevice bluetoothDevice = gatt.getDevice(); Log.d(TAG,"连接的设备:" + bluetoothDevice.getName() + " " + bluetoothDevice.getAddress()); isConnectIng = false; //移除连接超时 mHandler.removeCallbacks(connectOutTimeRunnable); if(newState == BluetoothGatt.STATE_CONNECTED) Log.w(TAG,"连接成功"); //连接成功去发现服务 gatt.discoverServices(); //设置发现服务超时时间 mHandler.postDelayed(serviceDiscoverOutTimeRunnable,MAX_CONNECT_TIME); if(onBleConnectListener != null) onBleConnectListener.onConnectSuccess(gatt,bluetoothDevice,status); //连接成功回调 else if(newState == BluetoothGatt.STATE_DISCONNECTED) //清空系统缓存 ClsUtils.refreshDeviceCache(gatt); Log.e(TAG, "断开连接status:" + status); gatt.close(); //断开连接释放连接 if(status == 133) //无法连接 if(onBleConnectListener != null) onBleConnectListener.onConnectFailure(gatt,bluetoothDevice,"连接异常!",status); //133连接异常 异常断开 Log.e(TAG,"连接失败status:" + status + " " + bluetoothDevice.getAddress()); else if(status == 62) //成功连接没有发现服务断开 if(onBleConnectListener != null) onBleConnectListener.onConnectFailure(gatt,bluetoothDevice,"连接成功服务未发现断开!",status); //62没有发现服务 异常断开 Log.e(TAG,"连接成功服务未发现断开status:" + status); else if(status == 0) if(onBleConnectListener != null) onBleConnectListener.onDisConnectSuccess(gatt,bluetoothDevice,status); //0正常断开 回调 else if(status == 8) //因为距离远或者电池无法供电断开连接 // 已经成功发现服务 if(onBleConnectListener != null) onBleConnectListener.onDisConnectSuccess(gatt,bluetoothDevice,status); //8断电断开 回调 else if(status == 34) if(onBleConnectListener != null) onBleConnectListener.onDisConnectSuccess(gatt,bluetoothDevice,status); //34断开 else //其它断开连接 if(onBleConnectListener != null) onBleConnectListener.onDisConnectSuccess(gatt,bluetoothDevice,status); //其它断开 else if(newState == BluetoothGatt.STATE_CONNECTING) Log.d(TAG,"正在连接..."); if(onBleConnectListener != null) onBleConnectListener.onConnecting(gatt,bluetoothDevice); //正在连接回调 else if(newState == BluetoothGatt.STATE_DISCONNECTING) Log.d(TAG,"正在断开..."); if(onBleConnectListener != null) onBleConnectListener.onDisConnecting(gatt,bluetoothDevice); //正在断开回调 //发现服务 @Override public void onServicesDiscovered(BluetoothGatt gatt, int status) super.onServicesDiscovered(gatt, status); //移除发现服务超时 mHandler.removeCallbacks(serviceDiscoverOutTimeRunnable); Log.d(TAG,"移除发现服务超时"); Log.d(TAG,"发现服务"); //获取特定服务及特征 if(setupService(gatt,serviceUUID,readUUID,writeUUID)) if(onBleConnectListener != null) onBleConnectListener.onServiceDiscoverySucceed(gatt,gatt.getDevice(),status); //成功发现服务回调 else if(onBleConnectListener != null) onBleConnectListener.onServiceDiscoveryFailed(gatt,gatt.getDevice(),"获取服务特征异常"); //发现服务失败回调 @Override public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) super.onCharacteristicRead(gatt, characteristic, status); Log.d(TAG,"读status: " + status); //向蓝牙设备写入数据结果回调 @Override public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) super.onCharacteristicWrite(gatt, characteristic, status); if(characteristic.getValue() == null) Log.e(TAG,"characteristic.getValue() == null"); return; //将收到的字节数组转换成十六进制字符串 String msg = TypeConversion.bytes2HexString(characteristic.getValue(),characteristic.getValue().length); if(status == BluetoothGatt.GATT_SUCCESS) //写入成功 Log.w(TAG,"写入成功:" + msg); if(onBleConnectListener != null) onBleConnectListener.onWriteSuccess(gatt,gatt.getDevice(),characteristic.getValue()); //写入成功回调 else if(status == BluetoothGatt.GATT_FAILURE) //写入失败 Log.e(TAG,"写入失败:" + msg); if(onBleConnectListener != null) onBleConnectListener.onWriteFailure(gatt,gatt.getDevice(),characteristic.getValue(),"写入失败"); //写入失败回调 else if(status == BluetoothGatt.GATT_WRITE_NOT_PERMITTED) //没有权限 Log.e(TAG,"没有权限!"); //读取蓝牙设备发出来的数据回调 @Override public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) super.onCharacteristicChanged(gatt, characteristic); //接收数据 byte[] bytes = characteristic.getValue(); Log.w("TAG","收到数据str:" + TypeConversion.bytes2HexString(bytes,bytes.length)); if(onBleConnectListener != null) onBleConnectListener.onReceiveMessage(gatt,gatt.getDevice(),characteristic,characteristic.getValue()); //接收数据回调 @Override public void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) super.onDescriptorRead(gatt, descriptor, status); @Override public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) super.onDescriptorWrite(gatt, descriptor, status); @Override public void onReliableWriteCompleted(BluetoothGatt gatt, int status) super.onReliableWriteCompleted(gatt, status); Log.d(TAG,"onReliableWriteCompleted"); @Override public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) super.onReadRemoteRssi(gatt, rssi, status); if(status == BluetoothGatt.GATT_SUCCESS) Log.w(TAG,"读取RSSI值成功,RSSI值:" + rssi + ",status" + status); if(onBleConnectListener != null) onBleConnectListener.onReadRssi(gatt,rssi,status); //成功读取连接的信号强度回调 else if(status == BluetoothGatt.GATT_FAILURE) Log.w(TAG,"读取RSSI值失败,status:" + status); //修改MTU值结果回调 @Override public void onMtuChanged(BluetoothGatt gatt, int mtu, int status) super.onMtuChanged(gatt, mtu, status); ///设置mtu值,即bluetoothGatt.requestMtu()时触发,提示该操作是否成功 if(status == BluetoothGatt.GATT_SUCCESS) //设置MTU成功 //MTU默认取的是23,当收到 onMtuChanged 后,会根据传递的值修改MTU,注意由于传输用掉3字节,因此传递的值需要减3。 //mtu - 3 Log.w(TAG,"设置MTU成功,新的MTU值:" + (mtu-3) + ",status" + status); if(onBleConnectListener != null) onBleConnectListener.onMTUSetSuccess("设置后新的MTU值 = " + (mtu-3) + " status = " + status,mtu - 3); //MTU设置成功 else if(status == BluetoothGatt.GATT_FAILURE) //设置MTU失败 Log.e(TAG,"设置MTU值失败:" + (mtu-3) + ",status" + status); if(onBleConnectListener != null) onBleConnectListener.onMTUSetFailure("设置MTU值失败:" + (mtu-3) + " status:" + status); //MTU设置失败 ; /** * 通过蓝牙设备连接 * @param context 上下文 * @param bluetoothDevice 蓝牙设备 * @param outTime 连接超时时间 * @param onBleConnectListener 蓝牙连接监听者 * @return */ @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2) public BluetoothGatt connectBleDevice(Context context, BluetoothDevice bluetoothDevice, long outTime,OnBleConnectListener onBleConnectListener) if(bluetoothDevice == null) Log.e(TAG,"addBLEConnectDevice-->bluetoothDevice == null"); return null; this.onBleConnectListener = onBleConnectListener; this.curConnDevice = bluetoothDevice; Log.d(TAG,"开始准备连接:" + bluetoothDevice.getName() + "-->" + bluetoothDevice.getAddress()); //出现 BluetoothGatt.android.os.DeadObjectException 蓝牙没有打开 try if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) mBluetoothGatt = bluetoothDevice.connectGatt(context, false, bluetoothGattCallback, BluetoothDevice.TRANSPORT_LE,BluetoothDevice.PHY_LE_1M_MASK); else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) mBluetoothGatt = bluetoothDevice.connectGatt(context, false, bluetoothGattCallback, BluetoothDevice.TRANSPORT_LE); else mBluetoothGatt = bluetoothDevice.connectGatt(context, false, bluetoothGattCallback); catch(Exception e) Log.e(TAG,"e:" + e.getMessage()); mHandler.postDelayed(connectOutTimeRunnable,outTime); return mBluetoothGatt; //连接超时 private Runnable connectOutTimeRunnable = new Runnable() @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2) @Override public void run() if(mBluetoothGatt == null) Log.e(TAG,"connectOuttimeRunnable-->mBluetoothGatt == null"); return; isConnectIng = false; mBluetoothGatt.disconnect(); //连接超时当作连接失败回调 if(onBleConnectListener != null) onBleConnectListener.onConnectFailure(mBluetoothGatt,curConnDevice,"连接超时!",-1); //连接失败回调 ; //发现服务超时 private Runnable serviceDiscoverOutTimeRunnable = new Runnable() @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2) @Override public void run() if(mBluetoothGatt == null) Log.e(TAG,"connectOuttimeRunnable-->mBluetoothGatt == null"); return; isConnectIng = false; mBluetoothGatt.disconnect(); //发现服务超时当作连接失败回调 if(onBleConnectListener != null) onBleConnectListener.onConnectFailure(mBluetoothGatt,curConnDevice,"发现服务超时!",-1); //连接失败回调 ;
(2)发现系统服务之后,还需要获取特定服务及读写特征才能进行数据通讯。一般,读特征是用来读取蓝牙设备发出来的数据,写特征是向蓝牙设备写入数据,其中,读特征一定要设置打开通知,否则接收不到消息。
/** * 获取特定服务及特征 * 1个serviceUUID -- 1个readUUID -- 1个writeUUID * @param bluetoothGatt * @param serviceUUID * @param readUUID * @param writeUUID * @return */ @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2) private boolean setupService(BluetoothGatt bluetoothGatt,String serviceUUID,String readUUID,String writeUUID) if (bluetoothGatt == null) Log.e(TAG, "setupService()-->bluetoothGatt == null"); return false; if(serviceUUID == null) Log.e(TAG, "setupService()-->serviceUUID == null"); return false; for (BluetoothGattService service : bluetoothGatt.getServices()) // Log.d(TAG, "service = " + service.getUuid().toString()); if (service.getUuid().toString().equals(serviceUUID)) bluetoothGattService = service; //通过上面方法获取bluetoothGattService // bluetoothGattService = bleManager.getBluetoothGattService(bluetoothGatt,ConsData.MY_BLUETOOTH4_UUID); if (bluetoothGattService == null) Log.e(TAG, "setupService()-->bluetoothGattService == null"); return false; Log.d(TAG, "setupService()-->bluetoothGattService = " + bluetoothGattService.toString()); if(readUUID == null || writeUUID == null) Log.e(TAG, "setupService()-->readUUID == null || writeUUID == null"); return false; for (BluetoothGattCharacteristic characteristic : bluetoothGattService.getCharacteristics()) if (characteristic.getUuid().toString().equals(readUUID)) //读特征 readCharacteristic = characteristic; else if (characteristic.getUuid().toString().equals(writeUUID)) //写特征 writeCharacteristic = characteristic; if (readCharacteristic == null) Log.e(TAG, "setupService()-->readCharacteristic == null"); return false; if (writeCharacteristic == null) Log.e(TAG, "setupService()-->writeCharacteristic == null"); return false; //打开读通知 enableNotification(true, bluetoothGatt, readCharacteristic); //重点中重点,需要重新设置 List<BluetoothGattDescriptor> descriptors = readCharacteristic.getDescriptors(); for (BluetoothGattDescriptor descriptor : descriptors) descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE); bluetoothGatt.writeDescriptor(descriptor); //延迟2s,保证所有通知都能及时打开 mHandler.postDelayed(new Runnable() @Override public void run() , 2000); return true; / 打开通知 // /** * 设置读特征接收通知 * @param enable 为true打开通知 * @param gatt 连接 * @param characteristic 特征 */ @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2) public void enableNotification(boolean enable, BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) if(gatt == null) Log.e(TAG,"enableNotification-->gatt == null"); return; if(characteristic == null) Log.e(TAG,"enableNotification-->characteristic == null"); return; //这一步必须要有,否则接收不到通知 gatt.setCharacteristicNotification(characteristic,enable);
5、数据通讯
(1)发送数据
mBluetoothGatt.writeCharacteristic()方法的返回值,并不能真正的表示数据是否发送成功,而是通过BluetoothGattCallback回调方法onCharacteristicWrite()来判断数据是否已成功写入底层。
//向蓝牙设备写入数据结果回调 @Override public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) super.onCharacteristicWrite(gatt, characteristic, status); if(characteristic.getValue() == null) Log.e(TAG,"characteristic.getValue() == null"); return; //将收到的字节数组转换成十六进制字符串 String msg = TypeConversion.bytes2HexString(characteristic.getValue(),characteristic.getValue().length); if(status == BluetoothGatt.GATT_SUCCESS) //写入成功 Log.w(TAG,"写入成功:" + msg); if(onBleConnectListener != null) onBleConnectListener.onWriteSuccess(gatt,gatt.getDevice(),characteristic.getValue()); //写入成功回调 else if(status == BluetoothGatt.GATT_FAILURE) //写入失败 Log.e(TAG,"写入失败:" + msg); if(onBleConnectListener != null) onBleConnectListener.onWriteFailure(gatt,gatt.getDevice(),characteristic.getValue(),"写入失败"); //写入失败回调 else if(status == BluetoothGatt.GATT_WRITE_NOT_PERMITTED) //没有权限 Log.e(TAG,"没有权限!");
/// 发送数据 /// /** * 发送消息 byte[]数组 * @param msg 消息 * @return true false */ @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2) public boolean sendMessage( byte[] msg) if(writeCharacteristic == null) Log.e(TAG,"sendMessage(byte[])-->writeGattCharacteristic == null"); return false; if(mBluetoothGatt == null) Log.e(TAG,"sendMessage(byte[])-->mBluetoothGatt == null"); return false; boolean b = writeCharacteristic.setValue(msg); Log.d(TAG, "写特征设置值结果:" + b); return mBluetoothGatt.writeCharacteristic(writeCharacteristic);
(2)接收数据
接收的数据是直接通过BluetoothGattCallback回调方法onCharacteristicChanged()来获取的。
//读取蓝牙设备发出来的数据回调 @Override public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) super.onCharacteristicChanged(gatt, characteristic); //接收数据 byte[] bytes = characteristic.getValue(); Log.w("TAG","收到数据str:" + TypeConversion.bytes2HexString(bytes,bytes.length)); if(onBleConnectListener != null) onBleConnectListener.onReceiveMessage(gatt,gatt.getDevice(),characteristic,characteristic.getValue()); //接收数据回调
6、断开连接
BLE通讯结束之后,需要及时断开连接,并且在断开连接的回调处释放资源。否则会导致下一次执行连接操作时,导致133异常。所以,一般连接出现133异常,都是因为断开后及时释放资源。
断开连接的结果是在BluetoothGattCallback回调方法onConnectionStateChange()来获取的。(可查看上面建立连接处的代码)
/// 断开连接 /// /** * 断开连接 */ @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2) public void disConnectDevice() if(mBluetoothGatt == null) Log.e(TAG,"disConnectDevice-->bluetoothGatt == null"); return; //系统断开 mBluetoothGatt.disconnect();
三、项目演示
(1)扫描目标设备(BLEyqy),点击“连接”按钮, 会在“搜索”按钮下方显示连接结果 。
(2)手机给目标设备发送数据成功之后,蓝牙设备把接收到的数据再回发送给手机。
(3)断开连接。点击“断开”按钮, 会在“搜索”按钮下方显示断开结果 。
四、Demo案例源码地址
码云:https://gitee.com/lilium_foliage/Android-Bluetooth-Low-Energy
CSDN:https://download.csdn.net/download/qq_38950819/12001139
五、更新记录
1、2020/12/29 :修改 setupService()中错误
2、2021/05/14 :更新连接方法(解决部分蓝牙设备连接失败的问题)
以上是关于Android蓝牙开发——BLE(低功耗蓝牙)(附完整Demo)的主要内容,如果未能解决你的问题,请参考以下文章
Android BLE低功耗蓝牙开发极简系列(二)之读写操作