【Android】蓝牙相关

本文详细介绍了在Android系统中进行蓝牙连接、扫描、消息发送和接收的步骤,包括权限设置、扫描设备、使用ViseBle库进行连接以及建立消息监听的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

权限

<!--android 6-11-->
  <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
    <uses-permission android:name="android.permission.BLUETOOTH"/>
    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
<!--android 12-->
    <!--蓝牙连接-->
   <uses-permission android:name="android.permission.BLUETOOTH_CONNECT"/>
    <!--蓝牙扫描-->
    <uses-permission android:name="android.permission.BLUETOOTH_SCAN"
        android:usesPermissionFlags="neverForLocation"
        tools:targetApi="s"/>

android 12以上声明 android:usesPermissionFlags="neverForLocation"后不需位置权限

扫描

 private static void startScanLeIfEnabled() {
        if(scanner==null) {
            BluetoothManager manager = (BluetoothManager) Utils.getApp().getSystemService(BLUETOOTH_SERVICE);
            BluetoothAdapter mBluetoothAdapter = manager.getAdapter();
            Log.i("testNet", "enable:" + mBluetoothAdapter.isEnabled());
            if (mBluetoothAdapter != null && mBluetoothAdapter.isEnabled()) {
                //  mBluetoothAdapter.startLeScan()
                scanner = mBluetoothAdapter.getBluetoothLeScanner();

            }else{
                ToastUtils.showShort("请开启蓝牙");
            }
        }
        scanner.startScan(scanCallback);
    }

    private static BluetoothLeScanner scanner;

使用 BluetoothScanner 调用startScan进行扫描,扫描会持续进行,直到调用 stopScan,回调结果在ScanCallback的 onScanResult中,每次返回一条,需做去重操作

连接

连接这里使用了第三方ViseBle,也可以自己实现

 ViseBle.getInstance().connectByMac(bleMAC, connectCallback);

在回调中拿到 List<BluetoothGattService> gattServices = deviceMirror.getBluetoothGatt().getServices();根据设备提供的服务码找到符合条件的BluetoothGattService

 List<BluetoothGattCharacteristic> gattCharacteristics = gattService.getCharacteristics();
switch (gattCharacteristics.get(i).getProperties()){
                                    case BluetoothGattCharacteristic.PROPERTY_READ://读取
                                        propertyType=PropertyType.PROPERTY_READ;
                                        break;
                                    case BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE://写 无返回
                                       // propertyType=PropertyType.PROPERTY_WRITE;
                                        continue;
                                       // break;
                                    case BluetoothGattCharacteristic.PROPERTY_WRITE://写

                                        propertyType=PropertyType.PROPERTY_WRITE;

                                        break;
                                    case BluetoothGattCharacteristic.PROPERTY_NOTIFY://通知
                                    case BluetoothGattCharacteristic.FORMAT_UINT16:
                                        propertyType=PropertyType.PROPERTY_NOTIFY;
                                        break;
                                    case BluetoothGattCharacteristic.PROPERTY_INDICATE://indicate 指令
                                        propertyType=PropertyType.PROPERTY_INDICATE;
                                        break;
                                }

从服务中拿到特征,根据特征的通道类型建立连接,读写等会有不同的回调,需要绑定多个渠道

bindChannel(bluetoothLeDevice,
                                            propertyType,
                                            serviceUUID,
                                            characterUUID,
                                            null);
 public void bindChannel(BluetoothLeDevice bluetoothLeDevice, PropertyType propertyType, UUID serviceUUID,
                            UUID characteristicUUID, UUID descriptorUUID) {
        DeviceMirror deviceMirror = mDeviceMirrorPool.getDeviceMirror(bluetoothLeDevice);
        if (deviceMirror != null) {
            Log.e(TAG, "serviceUUID:"+serviceUUID+" cUUID:"+characteristicUUID+" descriptorUUID:"+descriptorUUID+" properTyp:"+propertyType);
            BluetoothGattChannel bluetoothGattChannel = new BluetoothGattChannel.Builder()
                    .setBluetoothGatt(deviceMirror.getBluetoothGatt())
                    .setPropertyType(propertyType)
                    .setServiceUUID(serviceUUID)
                    .setCharacteristicUUID(characteristicUUID)
                    .setDescriptorUUID(descriptorUUID)
                    .builder();
            deviceMirror.bindChannel(bleCallback, bluetoothGattChannel);
            //if(propertyType==PropertyType.PROPERTY_INDICATE||propertyType==PropertyType.PROPERTY_NOTIFY) {
                deviceMirror.registerNotify(propertyType == PropertyType.PROPERTY_INDICATE);
            //}
//            Log.e(TAG, "getGattInfoKey:" + bluetoothGattChannel.getGattInfoKey());
//            deviceMirror.setNotifyListener(bluetoothGattChannel.getGattInfoKey(), receiveCallback);
        }
    }

消息发送

DeviceMirror deviceMirror = mDeviceMirrorPool.getDeviceMirror(bluetoothLeDevice);
        if(deviceMirror!=null) {
            deviceMirror.writeData(jsonString);
           // deviceMirror.
        }

消息接收

发出消息时建立消息的监听

DeviceMirror deviceMirror = mDeviceMirrorPool.getDeviceMirror(bluetoothLeDevice);
            deviceMirror.setNotifyListener(bluetoothGattInfo.getGattInfoKey(), receiveCallback);

在回调中获取设备返回的数据

 private IBleCallback receiveCallback = new IBleCallback() {
        @Override
        public void onSuccess(final byte[] data, BluetoothGattChannel bluetoothGattInfo, BluetoothLeDevice bluetoothLeDevice) {
            if (data == null) {
                return;
            }
            if(receiveListener!=null){
                receiveListener.onSuccess(data,bluetoothGattInfo,bluetoothLeDevice);
            }
            Log.e(TAG, "处理数据:"+new String(data));
            ToastUtils.showShort(new String(data));
            //此时进行获取数据的处理

        }

        @Override
        public void onFailure(BleException exception) {
            if (exception == null) {
                return;
            }
            Log.e(TAG, "数据接收失败:"+exception.toString());

        }
    };

状态判断

  1. 注册广播BluetoothDevice.ACTION_BOND_STATE_CHANGED,接收配对状态(只会在首次连接有回调,配对成功后,下次连接没有该回调)
BroadcastReceiver searchDevices=new BroadcastReceiver() {
        @SuppressLint("MissingPermission")
        @Override
        public void onReceive(Context context, Intent intent) {
            if(BluetoothDevice.ACTION_BOND_STATE_CHANGED.equals(intent.getAction())){
                BluetoothDevice  device=intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                Log.e("TAG", "onReceive:"+device.getBondState());
                switch (device.getBondState()){
                    case BluetoothDevice.BOND_BONDING://正在配对
                        LogUtils.i("连接中");
                        break;
                    case BluetoothDevice.BOND_BONDED://配对结束
                        LogUtils.i("已配对");
                        break;
                    case BluetoothDevice.BOND_NONE:
                        LogUtils.i("已解除配对");
                        break;
                }
            }
        }
    };

2.同理注册广播BluetoothDevice.ACTION_ACL_CONNECTED接收连接成功状态
3.由于连接状态是从 连接中—连接成功—配对成功 流转,当下次连接时不会走到配对成功的状态,连接成功即结束,所以要判断是否完成流程需在连接成功处判断是否已完成配对:

public static boolean checkPairDeviceContent(BluetoothDevice device) {
        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
        Set<BluetoothDevice> devices = adapter.getBondedDevices();
        return devices!=null&&devices.contains(device);
    }

特例

正常蓝牙连接使用GATT连接,在某些设备上会出现连接后系统层没有名称(应用层连上了,系统层没连上),连接配对出现多次配对弹窗等情况,可尝试使用反射建立配对,配对成功后再用gatt连接

 BluetoothDevice device = bluetoothAdapter.getRemoteDevice(mac);
        if (device != null) {
            if (!isBonding && device.getBondState() != BluetoothDevice.BOND_BONDED) {
                try {
                    Method method = device.getClass().getMethod("createBond");
                    method.invoke(device);
                    isBonding = true;
                } catch (Exception e) {
                    e.printStackTrace();
                }
                Log.e(TAG, "bluetoothGatt==配对中");
            }else{
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                    bluetoothGatt = device.connectGatt(context, true, bluetoothGattCallback, BluetoothDevice.TRANSPORT_LE);
                } else {
                    bluetoothGatt = device.connectGatt(context, true, bluetoothGattCallback);
                }
            }
        }

借鉴

implementation 'com.vise.xiaoyaoyou:baseble:2.0.6'
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值