安卓蓝牙开发

安卓ble蓝牙开发

2017-09-06  本文已影响84人  菜鸟超

1首先说一下BLE设备有什么东西:

  1. 一个BLE终端可以包含多个Service(服务)一个Service可以包含多个Characteristic(特征),一个Characteristic包含一个value和多个Descriptor(描述符),一个Descriptor包含一个Value。其中,我们要注意的是,每一个Service、Characteristic都会有一个uuid,这是一个唯一值,我们接下来的传输数据,将用到这个。每一个Characteristic都有一个Value,我们就是通过改变这个值,来对设备进行交互的。
  2. 说白了,ble开发主要就是找到指定的Service,Characteristic,然后通过写的Characteristic写入数据给蓝牙设备,通过通知的Characteristic读蓝牙设备返回的数据,通过读的Characteristic读取蓝牙设备的某些值。
    这些东西一般蓝牙文档中就会给出来,如下图:

当然如果没有文档可下载nrf master control panel 这个app根据协议文档进行测试,找出设备使用的Service和Characteristic。

2.在android中,对ble设备的操作实际上是对BluetoothGatt的操作,所以我们首先要想办法获取到BluetoothGatt。对蓝牙设备的连接过程也就是获取BluetoothGatt的获取过程,大概有以下几步:

  1. 添加权限(你也知道啦,想要连接ble设备,肯定得获取手机相关的权限使用权啦)
 <uses-permission android:name="android.permission.BLUETOOTH"/>
    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
    <uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/>
  1. 扫描Ble设备:想要扫描设备,首先我们先要拿到BluetoothManager,通过BluetoothManager的getAdapter()方法再拿到BluetoothAdapter,然后再通过BluetoothAdapter的startSacn( LeScanCallback)的方法开始扫描设备。值得注意的是,我们还需要实现LeScanCallback的回调方法。(这里可通过蓝牙名称或者蓝牙mac地址找到蓝牙设备)
private BluetoothAdapter.LeScanCallback mLeScanCallback = new BluetoothAdapter.LeScanCallback() {

                @Override
                public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) {
                    ULog.d(TAG,"onscan");
                    //  BluetoothDevice  name=eBody-Scale address=BC:6A:29:26:97:5E
                    ULog.d(TAG,"BluetoothDevice  name=" + device.getName() + " address=" + device.getAddress());
                    //  BluetoothDevice  name=eBody-Scale address=BC:6A:29:26:97:5E
                    //根据蓝牙名称或者mac地址找到对应的蓝牙设备
                    if (isScanByName){
                        if (name.equals(device.getName())) {
                            ULog.d(TAG,"find_device_by_name");
                            mBluetoothGatt = device.connectGatt(mContext, false, mGattCallback);
                            if (mScanning) {
                                scanLeDevice(false);
                            }

                        }
                    }else {
                        if (mac.equals(device.getAddress())) {
                            ULog.d(TAG,"find_device_by_mac");
                            mBluetoothGatt = device.connectGatt(mContext, false, mGattCallback);
                            if (mScanning) {
                                scanLeDevice(false);
                            }

                        }
                    }
                    
                }
    };

在其回调方法中会有这么一个函数,onLeScan(BluetoothDevice, rssi, byte[])。当中的bluetoothDevice就是我们扫描的设备;rssi是int类型,代表设备的信号强度,是负的,数值越大代表信号强度越大;byte[]这个byte数组就是设备广播的相关数据(在我们项目中,我们是依靠这个广播来判断我们设备时候在充电状态的,各个设备应该都有自己的商定)。

3.建立连接:当扫描到我们所需的设备,就可以开始建立连接了。主要是使用上面所扫描到设备的BluetoothDevice.connectGatt(context, boolean, BluetoothGattCallback)的方法进行连接,这个函数将返回BluetoothGatt的实例,到此,我们就拿到了BluetoothGatt了,就可以进行相关读写数据操作了。(连接之后关闭蓝牙扫描,蓝牙扫描很耗电和占用系统资源)BluetoothGattCallback抽象类,只有9个方法,字面意思就都可以看懂,在处理连接事件上,需要处理方法:比如连接状态:

 private BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
        @Override
        public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
            //连接成功判断
            if (newState == BluetoothProfile.STATE_CONNECTED) {

                ULog.d(TAG,"connected");
                btMsgCallBack.onConnected();
                mBluetoothGatt.discoverServices();
                // 连接断开判断
            } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
                ULog.d(TAG,"onDisConnected");
                btMsgCallBack.onDisConnected();
                gatt.close();

                //连接断开延时一秒后继续扫秒蓝牙连接
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                if (isScan)
                scanLeDevice(true);


            } else if (status != BluetoothGatt.GATT_SUCCESS) { // 连接失败判断
                ULog.d(TAG,"onConnectFail");
                btMsgCallBack.onConnectFail();

                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                if (isScan)
                    scanLeDevice(true);
            }
        }

其他几个回调就不说了,项目中有注释,大致可以去看下。。。

3.蓝牙连接成功后就可以找出我们指定的服务和通知的特征,写的特征,读的特征。//通知特征设置激活(有些设备特征值有很多个,要一个一个去激活)

   BluetoothGattCharacteristic characteristic = btService.getCharacteristic(UUID.fromString(notifyUUid[0]));
                if (characteristic != null) {
                    mBluetoothGatt.setCharacteristicNotification(characteristic, true);
                    BluetoothGattDescriptor descriptor = characteristic.getDescriptor(UUID.fromString(BleConfig.CLIENT_CHARACTERISTIC_CONFIG));
                    if (descriptor != null) {
                        descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
                        mBluetoothGatt.writeDescriptor(descriptor);
                    }
                  //  mBluetoothGatt.readCharacteristic(characteristic);
                }

成功后,蓝牙设备如果有数据就会回调onCharacteristicChanged(),我们这里接受处理数据即可(有的蓝牙设备还需要发送一条命令给他成功后才会返回数据)


        /**
         * 返回数据。
         */
        @Override
        public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
            // 数据
            ULog.d(TAG,"onCharacteristicChanged");
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < characteristic.getValue().length; i++) {
              //  sb.append (characteristic.getValue()[i] & 0xff).append(" ") ;   //变成int字符串数据,方便处理
               //这里也可变为16进制数据,方便对协议
                sb.append (String.format("%02X ",characteristic.getValue()[i] & 0xff)).append(" ") ;
            }

            btMsgCallBack.onReceiveMessage(sb.toString());

        }
    };

4.由于项目中经常用到,所以自己封装了一个,调用起来非常方便,代码已上传github.
//蓝牙辅助类初始化:

btMsgListener = BlueToothMessageListener.create(this).setCallback(btMsgCallBack)
                .setServiceUUid(DEVICE_SERVICE_UUID) //必须要
                .setNotifyUUid(NOTIFY_CHARACTERISTICSUUID)//必须要
                .setReadUUid(READ_CHARACTERISTICSUUID)
                .setWriteUUid(WRITE_CHARACTERISTICSUUID)
                .setBleName(DEVICE_NAME_SPO2) //蓝牙名称和mac地址二选一
                .setBleMac(DEVICE_MAC_SPO2);

github项目地址[bleUtils](https://github.com/tangchao5206/BleUtils本人水平有限,如果觉得还行,记得点赞.

上一篇下一篇

猜你喜欢

热点阅读