Android 蓝牙连接

作者: 进击的包籽 | 来源:发表于2018-06-20 09:35 被阅读63次

    最近因为公司的需求,要开发蓝牙的智能设备,通过网上查找资料,终于实现了蓝牙连接,通信的功能。

    重点1:蓝牙连接其实是不需要配对的!!!

    重点2:高版本Android系统,需要设置动态权限,除了蓝牙的一些控制权限,蓝牙搜索还需要定位权限。

    参考资料:
    Android开发之蓝牙详解(一)
    Android BLE开发详解和FastBle源码解析
    FastBle


    • 蓝牙状态广播,可以获取蓝牙打开,关闭状态。
    /**
     * 广播监听蓝牙状态
     */
    public class BlueToothValueReceiver extends BroadcastReceiver {
        public static int DEFAULT_VALUE_BULUETOOTH = 1000;
    
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(action)) {
                int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, DEFAULT_VALUE_BULUETOOTH);
                switch (state) {
                    case BluetoothAdapter.STATE_OFF:
                        LogUtils.d("蓝牙已关闭");
                        break;
                    case BluetoothAdapter.STATE_ON:
                        LogUtils.d("蓝牙已打开");
                        break;
                    case BluetoothAdapter.STATE_TURNING_ON:
                        LogUtils.d("正在打开蓝牙");
                        break;
                    case BluetoothAdapter.STATE_TURNING_OFF:
                        LogUtils.d("正在关闭蓝牙");
                        break;
                    default:
                        LogUtils.d("未知状态");
                }
            }
        }
    }
    
    //注册广播,蓝牙状态监听
    blueToothValueReceiver = new BlueToothValueReceiver();
    IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
    registerReceiver(blueToothValueReceiver, filter);
    
    蓝牙状态.jpg
    • 蓝牙搜索广播,可以获取到蓝牙的名称和物理地址,在未连接之前,拿不到uuid。
    /**
     * 蓝牙搜索
     */
    public class BlueToothFoundReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            //获取广播Action
            String action = intent.getAction();
            //判断广播是搜索到设备还是搜索完成
            if (BluetoothDevice.ACTION_FOUND.equals(action)) {
                // 找到设备后获取其设备
                BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                LogUtils.d("扫描到了:" + device.getName() + ":" + device.getAddress() + "\n");
            } else if (action.equals(BluetoothAdapter.ACTION_DISCOVERY_STARTED)) {
                LogUtils.e("搜索开启");
            } else if (action.equals(BluetoothAdapter.ACTION_DISCOVERY_FINISHED)) {
                LogUtils.e("搜索完成");
            }
        }
    }
    
    //蓝牙搜索
    blueToothFoundReceiver = new BlueToothFoundReceiver();
    IntentFilter filter_found = new IntentFilter(BluetoothDevice.ACTION_FOUND);
    filter_found.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED);
    filter_found.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
    registerReceiver(blueToothFoundReceiver, filter_found);
    
    广播结果.jpg
    • 蓝牙配对也有广播。
    /**
     * 蓝牙配对广播
     */
    public class BlueToothBondReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            if (intent.getAction().equals(BluetoothDevice.ACTION_BOND_STATE_CHANGED)) {
                // 找到设备后获取其设备
                BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                switch (device.getBondState()) {
                    case BluetoothDevice.BOND_BONDING:
                        //正在配对
                        LogUtils.d("正在配对");
                        break;
                    case BluetoothDevice.BOND_BONDED:
                        //配对结束
                        LogUtils.d("配对结束");
                        break;
                    case BluetoothDevice.BOND_NONE:
                        //取消配对/未配对
                        LogUtils.d("取消配对/未配对");
                    default:
                        break;
                }
            }
        }
    }
    

    • 除了这些广播,还有蓝牙工具,通过BluetoothAdapter.getDefaultAdapter();获取adapter,然后所有操作都基于这adapter。代码里面都有注释,很简单的,所以直接贴代码了。
    /**
     * 蓝牙工具类
     */
    public class BlueToothUtils {
        private Activity activity;
        private BluetoothAdapter bluetoothAdapter;
        //蓝牙是否可用
        private boolean bleEnable = false;
    
        public BlueToothUtils(Activity activity) {
            this.activity = activity;
            bleEnable = checkBlueToothEnable();
        }
    
        /**
         * 检测设备是否支持蓝牙
         */
        public boolean checkBlueToothEnable() {
            bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
            if (bluetoothAdapter == null) {
                ToastUtils.showShort("该设备不支持蓝牙");
                return false;
            } else {
                ToastUtils.showShort("该设备能支持蓝牙");
                return true;
            }
        }
    
        /**
         * 让用户去设置蓝牙
         */
        public void setBlueTooth() {
            if (bleEnable) {
                Intent blueTooth = new Intent(Settings.ACTION_BLUETOOTH_SETTINGS);
                activity.startActivity(blueTooth);
            }
        }
    
        /**
         * 打开蓝牙
         */
        public void onBlueTooth() {
            if (bleEnable) {
                if (bluetoothAdapter.isEnabled()) {
                    ToastUtils.showShort("蓝牙已打开,不用在点了~");
                } else {
                    bluetoothAdapter.enable();
                }
            }
        }
    
        /**
         * 关闭蓝牙
         */
        public void offBlueTooth() {
            if (bleEnable) {
                if (bluetoothAdapter.isEnabled()) {
                    bluetoothAdapter.disable();
                } else {
                    ToastUtils.showShort("蓝牙已关闭,不用在点了~");
                }
            }
        }
    
        /**
         * 获取已经配对的设备
         */
        public Set<BluetoothDevice> getConnectedDevices() {
            if (bleEnable) {
                if (bluetoothAdapter.isEnabled()) {
                    return bluetoothAdapter.getBondedDevices();
                }
            }
            return null;
        }
    
        /**
         * 可发现模式
         * 默认情况下,设备的可发现模式会持续120秒。
         * 通过给Intent对象添加EXTRA_DISCOVERABLE_DURATION附加字段,可以定义不同持续时间。
         * 应用程序能够设置的最大持续时间是3600秒
         */
        public void discoverableDuration() {
            Intent discoverableIntent = new
                    Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
            //定义持续时间
            discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);
            activity.startActivity(discoverableIntent);
        }
    
        /**
         * 扫描蓝牙,会走广播
         */
        public void startDiscovery() {
            if (bleEnable) {
                if (!bluetoothAdapter.isDiscovering()) {
                    bluetoothAdapter.startDiscovery();
                }
                ToastUtils.showShort("扫描蓝牙设备");
            }
        }
    
        /**
         * 停止扫描
         */
        public void stopDiscovery() {
            if (bleEnable) {
                if (bluetoothAdapter.isDiscovering()) {
                    bluetoothAdapter.cancelDiscovery();
                }
            }
        }
    
        /**
         * 扫描蓝牙
         */
        public void startScan() {
            if (bleEnable) {
                bluetoothAdapter.getBluetoothLeScanner().startScan(new ScanCallback() {
                    @Override
                    public void onScanResult(int callbackType, ScanResult result) {
                        //信号强度,是负的,数值越大代表信号强度越大
                        result.getRssi();
                        super.onScanResult(callbackType, result);
                    }
    
                    @Override
                    public void onBatchScanResults(List<ScanResult> results) {
                        super.onBatchScanResults(results);
                    }
    
                    @Override
                    public void onScanFailed(int errorCode) {
                        super.onScanFailed(errorCode);
                    }
                });
                ToastUtils.showShort("扫描蓝牙设备");
            }
        }
    
        /**
         * 停止扫描
         */
        public void stopScan() {
            if (bleEnable) {
                bluetoothAdapter.getBluetoothLeScanner().stopScan(new ScanCallback() {
                    @Override
                    public void onScanResult(int callbackType, ScanResult result) {
                        super.onScanResult(callbackType, result);
                    }
    
                    @Override
                    public void onBatchScanResults(List<ScanResult> results) {
                        super.onBatchScanResults(results);
                    }
    
                    @Override
                    public void onScanFailed(int errorCode) {
                        super.onScanFailed(errorCode);
                    }
                });
            }
        }
    
        /**
         * 连接设备
         */
        public void connectGatt(final BluetoothDevice device) {
            stopDiscovery();
            if (bleEnable) {
                device.connectGatt(activity, true, new BluetoothGattCallback() {
                    @Override
                    public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
                        switch (status) {
                            case BluetoothGatt.GATT_SUCCESS:
                                //连接成功
                                break;
                            case BluetoothProfile.STATE_CONNECTED:
                                //发现蓝牙服务
                                break;
                        }
                        super.onConnectionStateChange(gatt, status, newState);
                    }
                });
            }
        }
    }
    

    • 连上蓝牙是不需要配对的,可以从BluetoothGatt里获取信息,比如UUID。
    List<BluetoothGattService> serviceList = gatt.getServices();
    for (BluetoothGattService service : serviceList) {
        UUID uuid_service = service.getUuid();
    
        List<BluetoothGattCharacteristic> characteristicList = service.getCharacteristics();
        for (BluetoothGattCharacteristic characteristic : characteristicList) {
            UUID uuid_chara = characteristic.getUuid();
        }
    }
    

    • 用FastBle框架,可以接受蓝牙设备的通知。这里的uuid要么你用循环,遍历出能用的,然后存起来,要么直接让做设备的部门直接给你uuid。
    private void bleNotify(BleDevice bleDevice, BluetoothGatt gatt) {
        List<BluetoothGattService> serviceList = gatt.getServices();
        for (BluetoothGattService service : serviceList) {
            UUID uuid_service = service.getUuid();
    
            List<BluetoothGattCharacteristic> characteristicList = service.getCharacteristics();
            for (BluetoothGattCharacteristic characteristic : characteristicList) {
                UUID uuid_chara = characteristic.getUuid();
                BleManager.getInstance().notify(
                        bleDevice,
                        uuid_service.toString(),
                        uuid_chara.toString(),
                        new BleNotifyCallback() {
                            @Override
                            public void onNotifySuccess() {
                                // 打开通知操作成功
                                LogUtils.d("notify success");
                            }
    
                            @Override
                            public void onNotifyFailure(BleException exception) {
                                // 打开通知操作失败
                            }
    
                            @Override
                            public void onCharacteristicChanged(byte[] data) {
                                // 打开通知后,设备发过来的数据将在这里出现
                                LogUtils.d("Notify:" + HexUtil.encodeHexStr(data));
                            }
                        });
            }
        }
    }
    

    • 发送数据给蓝牙设备。也是一样样,获取相应的uuid。
    private void write(BleDevice bleDevice, BluetoothGatt gatt) {
        List<BluetoothGattService> serviceList = gatt.getServices();
        for (BluetoothGattService service : serviceList) {
            UUID uuid_service = service.getUuid();
    
            List<BluetoothGattCharacteristic> characteristicList = service.getCharacteristics();
            for (BluetoothGattCharacteristic characteristic : characteristicList) {
                UUID uuid_chara = characteristic.getUuid();
                BleManager.getInstance().write(
                        bleDevice,
                        uuid_service.toString(),
                        uuid_chara.toString(),
                        HexUtil.hexStringToBytes("0x5A"),
                        new BleWriteCallback() {
                            @Override
                            public void onWriteSuccess(int current, int total, byte[] justWrite) {
                            }
    
                            @Override
                            public void onWriteFailure(BleException exception) {
                            }
                        });
            }
        }
    }
    
    • 最后,像我做的这个蓝牙设备,是需要对数据编码和解码的,十六进制异或运算,大家可以根据自己的需求自己写,或者厂商给你的设备是会有文档的,多看看文档。

    相关文章

      网友评论

        本文标题:Android 蓝牙连接

        本文链接:https://www.haomeiwen.com/subject/wukaeftx.html