当前位置: 首页 > article >正文

android BLE 蓝牙的连接(二)

下面是基于实际的项目得到的具体步骤及核心代码

1、权限问题

先判断手机是否满足android4.3以上版本,再判断手机是否开启蓝牙 主要涉及蓝牙权限和位置权限,注意不同android版本之间权限申请的差异,以及android权限动态申请和静态申请的区别

//动态申请权限相关
private String[] requestPermissionArray = new String[]{
        Manifest.permission.ACCESS_FINE_LOCATION,
        Manifest.permission.ACCESS_COARSE_LOCATION,
        //Manifest.permission.ACCESS_BACKGROUND_LOCATION,
        Manifest.permission.BLUETOOTH,
        Manifest.permission.BLUETOOTH_ADMIN,
        Manifest.permission.BLUETOOTH_SCAN,
        Manifest.permission.BLUETOOTH_ADVERTISE,
        Manifest.permission.BLUETOOTH_CONNECT,
        Manifest.permission.WRITE_EXTERNAL_STORAGE,
        Manifest.permission.READ_EXTERNAL_STORAGE
};



/**
 * 初始化权限
 */
public void initNeedPermissions() {
    /**Android 6.0以上动态申请权限*/
    if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){
        final PermissionRequest permissionRequest = new PermissionRequest();
        permissionRequest.requestRuntimePermission(MainActivity.this, requestPermissionArray, new PermissionListener() {
            @Override
            public void onGranted() {
                Log.d(TAG,"所有权限已被授予");
            }

            /**用户勾选“不再提醒”拒绝权限后,关闭程序再打开程序只进入该方法!*/
            @Override
            public void onDenied(List<String> deniedPermissions) {
                deniedPermissionList = deniedPermissions;
                for (String deniedPermission : deniedPermissionList) {
                    Log.e(TAG,"被拒绝权限:" + deniedPermission);
                }
            }
        });
    }
}

 静态权限

    <uses-feature android:name="android.hardware.camera" /> 
    <uses-feature android:name="android.hardware.camera.autofocus" /> 
    <uses-permission android:name="android.permission.BLUETOOTH" /> 
    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /> 
    <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
    <uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
    <uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />
    <uses-permission android:name="android.permission.READ_CONTACTS" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> 
    <uses-permission android:name="android.permission.INTERNET" />

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、搜索设备

搜索蓝牙:搜索蓝牙,回调接口中查看ble设备相关信息,一定时间停止扫描 扫描设备是耗时的操作,一旦扫描结束,就要及时停止扫描。

    //扫描设备
    //扫描设备回调
    @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();
    }

 7、过程中遇到过的实际问题

暂无


http://www.kler.cn/news/311377.html

相关文章:

  • AI生成内容:优点与缺点
  • Docker实操:安装MySQL5.7详解(保姆级教程)
  • 【软考】数据字典(DD)
  • 游戏、网关等服务借助Docker容器化并使用Kubernetes部署、更新等
  • MySQL 中的 EXPLAIN 命令:洞察查询性能的利器
  • MySQL 中的索引覆盖扫描:加速查询的秘密武器
  • 【Linux】Ubuntu 22.04 shell实现MySQL5.7 tar 一键安装
  • 独立站技能树之建站33项自检清单 1.0丨出海笔记
  • STM32 HAL freertos零基础(十一)中断管理
  • Linux技术04-IPVS
  • 游戏如何对抗定制挂
  • Linux线程基础
  • Java-测试-Mockito 入门篇
  • FTP、SFTP安装,整合Springboot教程
  • 基于剪切板的高速翻译工具
  • 【Qt | QAction】Qt 的 QAction 类介绍
  • 电脑键盘功能基础知识汇总
  • Leetcode面试经典150题-130.被围绕的区域
  • MySql-单表以及多表查询详解
  • paddle 分类网络
  • 【Linux】【Vim】Vim 基础
  • Doris相关记录
  • 【计算机基础题目】二叉树的前序中序后续遍历之间相互转换 详细例子
  • 我的demo保卫萝卜中的技术要点
  • O1-preview:智能预测与预取驱动的性能优化处理器设计OPEN AI
  • Semaphore UI --Ansible webui
  • 心觉:成功学就像一把刀,有什么作用关键在于使用者(二)
  • 进入C++
  • Spring WebFlux实践与源码解析
  • leetcode41. 缺失的第一个正数,原地哈希表