# Android BLE **Repository Path**: null_446_4477/android-ble ## Basic Information - **Project Name**: Android BLE - **Description**: android平台上连接ble(蓝牙低功耗设备)的demo,包含打开、扫描蓝牙、连接、通信、断开连接各种功能。 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 4 - **Created**: 2021-08-05 - **Last Updated**: 2021-08-05 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 一、蓝牙BLE - 蓝牙是一种短距的无线通讯技术,可实现固定设备、移动设备之间的数据交换。一般将蓝牙3.0之前的BR/EDR蓝牙称为传统蓝牙,而将蓝牙4.0规范下的LE蓝牙称为低功耗蓝牙(BLE)。 - 蓝牙4.0标准包括传统蓝牙模块部分和低功耗蓝牙模块部分,是一个双模标准。低功耗蓝牙也是建立在传统蓝牙基础之上发展起来的,并区别于传统模块,最大的特点就是成本和功耗降低,应用于实时性要求比较高。 - 在BLE协议中,有两个角色,周边(Periphery)和中央(Central);周边是数据提供者,中央是数据使用/处理者,一个中央可以同时连接多个周边,但是一个周边某一时刻只能连接一个中央。 首先使用蓝牙就不得不说BluetoothGatt和BluetoothGattCallback这两个类,该类继承自BluetoothProfile,BluetoothGatt作为中央来使用和处理数据,通过BluetoothGatt可以连接设备(connect),发现服务(discoverServices),并把相应地属性返回到BluetoothGattCallback,BluetoothGattCallback返回中央的状态和周边提供的数据。 # 二、开发BLE安卓应用 - 参考网址https://www.jianshu.com/p/2dba7f067372,android蓝牙BLE(一) —— 扫描 - 新建工程。在工程的AndroidManifest添加蓝牙权限 ``` ``` 在Activity也要动态申请权限,添加下面代码,在启动蓝牙功能前调用initPermission方法申请权限。 ``` //申请多个权限 //1、首先声明一个数组permissions,将需要的权限都放在里面 String[] permissions = new String[]{Manifest.permission.ACCESS_FINE_LOCATION,Manifest.permission.ACCESS_COARSE_LOCATION}; //2、创建一个mPermissionList,逐个判断哪些权限未授予,未授予的权限存储到mPerrrmissionList中 List mPermissionList = new ArrayList<>(); private final int mRequestCode = 200;//权限请求码 //权限判断和申请 private void initPermission() { mPermissionList.clear();//清空没有通过的权限 //逐个判断你要的权限是否已经通过 for (int i = 0; i < permissions.length; i++) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (checkSelfPermission( permissions[i]) != PackageManager.PERMISSION_GRANTED) { mPermissionList.add(permissions[i]);//添加还未授予的权限 } } } //申请权限 if (mPermissionList.size() > 0) {//有权限没有通过,需要申请 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { requestPermissions(permissions, mRequestCode); } } } @Override public void onRequestPermissionsResult(int permsRequestCode, String[] permissions, int[] grantResults) { switch (permsRequestCode) { case 200:{ initPermission(); }break; } } ``` - 获取BluetoothManager和BluetoothAdapt,BluetoothAdapt具备启动蓝牙和扫描蓝牙列表的功能。 ``` //首先获取BluetoothManager BluetoothManager bluetoothManager=(BluetoothManager)getSystemService(Context.BLUETOOTH_SERVICE); //获取BluetoothAdapter BluetoothAdapter mBluetoothAdapter = bluetoothManager.getAdapter(); ``` - 判断蓝牙是否开启,蓝牙开启后开始扫描。 ``` if (!mBluetoothAdapter.isEnabled()) { boolean enable = mBluetoothAdapter.enable(); //返回值表示 是否成功打开了蓝牙功能 if (enable){ return; } } if(android.os.Build.VERSION.SDK_INT >= 21) { //标记当前的为扫描状态 mScanning = true; //获取5.0新添的扫描类 if (mBLEScanner == null){ //mBLEScanner是5.0新添加的扫描类,通过BluetoothAdapter实例获取。 mBLEScanner = mBluetoothAdapter.getBluetoothLeScanner(); } //开始扫描 //mScanCallback是ScanCallback实例。 mBLEScanner.startScan(mScanCallback); } else { //标记当前的为扫描状态 mScanning = true; //5.0以下 开始扫描 //mLeScanCallback是BluetoothAdapter.LeScanCallback实例 mBluetoothAdapter.startLeScan(mLeScanCallback); } //超过SCAN_TIME时间后停止搜索 mHandler.postDelayed(new Runnable() { @Override public void run() { //停止扫描设备 if(android.os.Build.VERSION.SDK_INT >= 21) { //标记当前的为未扫描状态 mScanning = false; mBLEScanner.stopScan(mScanCallback); } else { //标记当前的为未扫描状态 mScanning = false; //5.0以下 停止扫描 mBluetoothAdapter.stopLeScan(mLeScanCallback); } } }, SCAN_TIME); ``` - 扫描的方法需要提供对应的callback,callback类里面的函数里面可以得到扫描得到的蓝牙列表。可以用个列表数组添加扫描得到的设备,记得在开始扫描蓝牙前把列表数组清空。 ``` /** * 搜索蓝牙的结果 */ private BluetoothAdapter.LeScanCallback mLeScanCallback = new BluetoothAdapter.LeScanCallback() { @Override public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) { //在这里可以把搜索到的设备保存起来 //device.getName();获取蓝牙设备名字 //device.getAddress();获取蓝牙设备mac地址 //这里的rssi即信号强度,即手机与设备之间的信号强度。 if(device.getName()==null){ return; } for(int i=0; i results) { super.onBatchScanResults(results); } //当扫描不能开启时回调 @Override public void onScanFailed(int errorCode) { super.onScanFailed(errorCode); //扫描太频繁会返回ScanCallback.SCAN_FAILED_APPLICATION_REGISTRATION_FAILED,表示app无法注册,无法开始扫描。 //android 7.0后不能在30秒内扫描次数超过5次 } }; ``` - 得到蓝牙设备的列表数据后,一般是让用户选择好要连接的设备名称,根据对应的地址获取蓝牙设备BluetoothDevice后,调用连接connectGatt方法进行连接,并获得返回的BluetoothGatt。 ``` final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address); mBluetoothGatt = device.connectGatt(getActivity(), false, mGattCallback);//真正的连接。这个方法需要三个参数:一个Context对象,自动连接(boolean值,表示只要BLE设备可用是否自动连接到它) ``` - 连接蓝牙设备时需要提供对应的callback,callback类提供了各种连接状态和结果的回调方法。onConnectionStateChange可以得到蓝牙设备连接的状态,可以判断对应蓝牙设备是连接还是断开,连接成功后调用discoverServices方法。onServicesDiscovered可以得到发现的service和service包含的Characteristic,需要调用mBluetoothGatt.discoverServices()。蓝牙发送和接收数据是对Characteristic进行操作,如果没有确定的service和characteristic的UUID,就遍历characteristic获得可写和可读的characteristic存储起来,如果有确定的UUID就只存储对应的characteristic。onCharacteristicWrite可以知道写入到蓝牙外设的特征值是否成功,需要调用mBluetoothGatt.writeCharacteristic。onCharacteristicRead可以得到蓝牙外设发送的特征值,需要调用mBluetoothGatt.readCharacteristic。但是由于不知道蓝牙外设什么时候发送特征值,所以一般不会使用mBluetoothGatt.readCharacteristic方法,而是对Characteristic进行监听。onCharacteristicChanged可以监听到蓝牙外设有发送特征值并得到对应特征值,需要调用mBluetoothGatt.setCharacteristicNotification和mBluetoothGatt.writeDescriptor启动监听,前提是该Characteristic具有NOTIFY属性 ``` //定义蓝牙Gatt回调类 public class daqiBluetoothGattCallback extends BluetoothGattCallback{ //连接状态回调 @Override public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) { super.onConnectionStateChange(gatt, status, newState); // status 用于返回操作是否成功,会返回异常码。 // newState 返回连接状态,如BluetoothProfile#STATE_DISCONNECTED、BluetoothProfile#STATE_CONNECTED //操作成功的情况下 if (status == BluetoothGatt.GATT_SUCCESS){ //判断是否连接码 if (newState == BluetoothProfile.STATE_CONNECTED) { }else if(newState == BluetoothProfile.STATE_DISCONNECTED){ //判断是否断开连接码 } }else{ //异常码 } } //服务发现回调 @Override public void onServicesDiscovered(BluetoothGatt gatt, int status) { super.onServicesDiscovered(gatt, status); } //特征写入回调 @Override public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { super.onCharacteristicWrite(gatt, characteristic, status); } //外设特征值改变回调 @Override public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) { super.onCharacteristicChanged(gatt, characteristic); } //描述写入回调 @Override public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) { super.onDescriptorWrite(gatt, descriptor, status); } //特征读取回调 @Override public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { super.onCharacteristicRead(gatt, characteristic, status); } } ``` - 对Characteristic设置监听,当特征值改变时,接收到蓝牙外设发送的值,onCharacteristicChanged方法会回调 ``` for (int i=0; i gattDescriptors = characteristic.getDescriptors(); for (BluetoothGattDescriptor gattDescriptor : gattDescriptors) { gattDescriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE); mBluetoothGatt.writeDescriptor(gattDescriptor); } } ``` - 发送给蓝牙外设数据 ``` for (int i=0; i> fourWriteCharacteristicArrayList = new ArrayList<>(); private List> fourReadCharacteristicArrayList = new ArrayList<>(); private List> fourNotifyCharacteristicArrayList = new ArrayList<>(); ```