Android BLE低功耗蓝牙开发

    xiaoxiao2022-07-03  154

     Android蓝牙开发前,首先要区分是经典蓝牙开发还是BLE(低功耗)蓝牙开发,它们的开发是有区别的,如果还分不清经典蓝牙和BLE(低功耗)蓝牙的小伙伴,可以先问问度娘。

    开发流程:

    开启蓝牙扫描蓝牙配对蓝牙连接蓝牙通信

    1.先获取蓝牙的服务对象

    private BluetoothManager bluetoothManager(Context context) { return (BluetoothManager) context.getSystemService(Context.BLUETOOTH_SERVICE); }

    2.获取BluetoothAdapter对象

    public BluetoothAdapter getBluetoothAdapter(Context context) { return bluetoothManager(context).getAdapter(); }

    3.查看设备支不支持蓝牙功能

    /** * 设备是否支持蓝牙 true为支持 * * @return */ public boolean isSupportBlue(Context context) { return null != getBluetoothAdapter(context); }

    4.开启蓝牙权限

    /**  * 自动打开蓝牙(异步:蓝牙不会立刻就处于开启状态)  * 这个方法打开蓝牙不会弹出提示  */ public void openBlueAsyn(){     if (isSupportBlue()) {         mBluetoothAdapter.enable();     } }

    /**  * 自动打开蓝牙(同步)  * 这个方法打开蓝牙会弹出提示  * 需要在onActivityResult 方法中判断resultCode == RESULT_OK  true为成功  */ public void openBlueSync(Activity activity, int requestCode){     Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);     activity.startActivityForResult(intent, requestCode); }

    记得添加权限啊:

    <!-- 使用蓝牙的权限 --> <uses-permission android:name="android.permission.BLUETOOTH" /> <!-- 扫描蓝牙设备或者操作蓝牙设置 --> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /> <!--模糊定位权限,仅作用于6.0+--> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <!--精准定位权限,仅作用于6.0+--> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />  

    话不多说直接copy吧,至于为什么要加定位权限。我也没有深究,这里6.0+记得加上动态申请定位权限的。不加,你懂的。。

     

    在这之后才开始扫描蓝牙设备;扫描有低功耗扫描和经典扫描之分;

    public BLEManager scanBle(Context context) { bluetoothLeScanner = getBluetoothAdapter(context).getBluetoothLeScanner(); bluetoothLeScanner.startScan(scanCallback); return this; } /** * 扫描回调 */ ScanCallback scanCallback = new ScanCallback() { @Override public void onScanResult(int callbackType, ScanResult result) { super.onScanResult(callbackType, result); BluetoothDevice device = result.getDevice(); if (null != device && !TextUtils.isEmpty(device.getName()) && device.getName().contains("过滤")) { Log.d("onScanResult", "onScanResult==" + device.getName() + "address=" + device.getAddress()); bluetoothDevicesSet.add(device); bluetoothDeviceList.clear(); bluetoothDeviceList.addAll(bluetoothDevicesSet); if (null != onBluetoothReciver) { onBluetoothReciver.onSearchResult(bluetoothDevicesSet, bluetoothDeviceList); } } } @Override public void onBatchScanResults(List<ScanResult> results) { super.onBatchScanResults(results); } @Override public void onScanFailed(int errorCode) { super.onScanFailed(errorCode); } }; public void scan(Context context){ //TODO该方式已经过时,推荐使用第一种 getBluetoothAdapter(context).startLeScan(new BluetoothAdapter.LeScanCallback() { @Override public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) { } }); }

    经典的就不贴了。

    这个时候你已经能获取到你要扫描的设备;

    开始连接:

    连接模式是固定的;通过扫描到的设备发起连接,并设置一个GattCallBack即可。通过这个callback,我们可以获取到

    当前设备的连接状态 onConnectionStateChange、设备服务对象onServicesDiscovered包括该服务的一下特征uuid等

    onCharacteristicChanged当设备特征发生改变时回回调该方法。可在这里接收蓝牙设备发过来的数据。

    device.createBond();//配对,天仙配之后才能连接(目前我做的不用配对,嘿嘿) public DeviceConnetMannager connet(Context context, BluetoothDevice device) { bluetoothGatt = device.connectGatt(context, true, mGattCallback); return this; } private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() { @Override public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) { if (null != bleStatusChange) { bleStatusChange.statusChange(gatt, newState); } if (newState == BluetoothProfile.STATE_CONNECTED) { mConnectionState = STATE_CONNECTED; bluetoothGatt.discoverServices(); } else if (newState == BluetoothProfile.STATE_DISCONNECTED) { mConnectionState = STATE_DISCONNECTED; } } @Override public void onServicesDiscovered(BluetoothGatt gatt, int status) { if (status == BluetoothGatt.GATT_SUCCESS) { List<BluetoothGattService> services = bluetoothGatt.getServices(); for (int i = 0; i < services.size(); i++) { HashMap<String, BluetoothGattCharacteristic> charMap = new HashMap<>(); BluetoothGattService bluetoothGattService = services.get(i); String serviceUuid = bluetoothGattService.getUuid().toString(); List<BluetoothGattCharacteristic> characteristics = bluetoothGattService.getCharacteristics(); for (int j = 0; j < characteristics.size(); j++) { charMap.put(characteristics.get(j).getUuid().toString(), characteristics.get(j)); } servicesMap.put(serviceUuid, charMap); } BluetoothGattCharacteristic bluetoothGattCharacteristic = getBluetoothGattCharacteristic(UUID_SERVICE, UUID_CHARACTERISTIC); if (bluetoothGattCharacteristic == null) { return; } enableGattServicesNotification(bluetoothGattCharacteristic); } else { Log.w(TAG, " --------- onServicesDiscovered received: " + status); } } @Override public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { Log.d(TAG, "onCharacteristicRead: status---=" + status); if (status == BluetoothGatt.GATT_SUCCESS) { } } @Override public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) { String s = Arrays.toString(characteristic.getValue()); Log.d("收到数据=", "onCharacteristicChanged: -----------=" + s); if (null != MessageMannager.build().getReciverData()) { MessageMannager.build().getReciverData().parseData(characteristic); } } }; /** * 根据服务UUID和特征UUID,获取一个特征{@link BluetoothGattCharacteristic} * * @param serviceUUID 服务UUID * @param characterUUID 特征UUID */ private BluetoothGattCharacteristic getBluetoothGattCharacteristic(String serviceUUID, String characterUUID) { if (!isEnable(context)) { throw new IllegalArgumentException(" Bluetooth is no enable please call BluetoothAdapter.enable()"); } if (null == bluetoothGatt) { Log.e(TAG, "mBluetoothGatt is null"); return null; } //找服务 Map<String, BluetoothGattCharacteristic> bluetoothGattCharacteristicMap = servicesMap.get(serviceUUID); if (null == bluetoothGattCharacteristicMap) { Log.e(TAG, "Not found the serviceUUID!"); return null; } //找特征 Set<Map.Entry<String, BluetoothGattCharacteristic>> entries = bluetoothGattCharacteristicMap.entrySet(); BluetoothGattCharacteristic gattCharacteristic = null; for (Map.Entry<String, BluetoothGattCharacteristic> entry : entries) { if (characterUUID.equals(entry.getKey())) { gattCharacteristic = entry.getValue(); break; } } return gattCharacteristic; } /** * 当前蓝牙是否打开 */ private boolean isEnable(Context c) { if (null != BLEManager.build().getBluetoothAdapter(c)) { return BLEManager.build().getBluetoothAdapter(c).isEnabled(); } return false; } private void enableGattServicesNotification(BluetoothGattCharacteristic gattCharacteristic) { if (gattCharacteristic == null) { return; } setNotify(gattCharacteristic); } private void setNotify(BluetoothGattCharacteristic characteristic) { final int charaProp = characteristic.getProperties(); if ((charaProp | BluetoothGattCharacteristic.PROPERTY_READ) > 0) { // If there is an active notification on a characteristic, clear // it first so it doesn't update the data field on the user interface. if (mNotifyCharacteristic1 != null) { setCharacteristicNotification( mNotifyCharacteristic1, false); mNotifyCharacteristic1 = null; } readCharacteristic(characteristic); } if ((charaProp | BluetoothGattCharacteristic.PROPERTY_NOTIFY) > 0) { mNotifyCharacteristic1 = characteristic; setCharacteristicNotification( characteristic, true); } } /** * Enables or disables notification on a give characteristic. * * @param characteristic Characteristic to act on. * @param enabled If true, enable notification. False otherwise. */ public void setCharacteristicNotification(BluetoothGattCharacteristic characteristic, boolean enabled) { if (BLEManager.build().getBluetoothAdapter(context) == null || bluetoothGatt == null) { Log.w(TAG, " --------- BluetoothAdapter not initialized --------- "); return; } bluetoothGatt.setCharacteristicNotification(characteristic, enabled); if (UUID_CHARACTERISTIC.equals(characteristic.getUuid().toString())) { BluetoothGattDescriptor descriptor = characteristic.getDescriptor( UUID.fromString(UUID_DESCRIPTOR)); descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE); bluetoothGatt.writeDescriptor(descriptor); Log.d(TAG, " --------- Connect setCharacteristicNotification --------- " + characteristic.getUuid()); } } /** * Request a read on a given {@code BluetoothGattCharacteristic}. The read result is reported * asynchronously through the {@code BluetoothGattCallback#onCharacteristicRead(android.bluetooth.BluetoothGatt, android.bluetooth.BluetoothGattCharacteristic, int)} * callback. * * @param characteristic The characteristic to read from. */ public void readCharacteristic(BluetoothGattCharacteristic characteristic) { if (BLEManager.build().getBluetoothAdapter(context) == null || bluetoothGatt == null) { Log.w(TAG, " --------- BluetoothAdapter not initialized --------- "); return; } bluetoothGatt.readCharacteristic(characteristic); }

    以上,就能接收外围设备发过来的数据了。

    怎么发送给设备:

    通过连接蓝牙时返回的BluetoothGatt 对象可以获取到该设备的服务对象即BluetoothGattService,这里BluetoothGattService还不能直接操作发送数据,因为BluetoothGattService没有设置数据的方法只能通过bluetoothGattCharacteristic 特性描述添加数据。

    然后再由BluetoothGatt 发送bluetoothGattCharacteristic 携带的数据给蓝牙设备。

    public boolean writeRXCharacteristic(byte... value) { //这里的mBluetoothGattService 是通过mBluetoothGatt.getService(RX_SERVICE_UUID)获取; //bluetoothGattCharacteristic 是通过mBluetoothGattService.getCharacteristic(RX_CHAR_UUID); 这里的两个UUID一般是固定。硬件给定 if (mBluetoothGatt == null) { return false; } if (mBluetoothGattService == null) { return false; } if (bluetoothGattCharacteristic == null) { return false; } if (!isConnet) { return false; } bluetoothGattCharacteristic.setValue(value); boolean status = mBluetoothGatt.writeCharacteristic(bluetoothGattCharacteristic); Log.d(TAG, "write TXchar - status=" + status); return status; }

    剩下的就是具体的封装通用代码了,我们项目要外接四个设备。所以简单封装了一个基类代码。上面差不多都摘出来的核心代码。

    到此最简单的通信完成,剩下的坑慢慢踩。核心代码都在了,就不给demo了。撒U拉纳

     

     

     

    最新回复(0)