Android蓝牙BLE入门

作者: tmyzh | 来源:发表于2018-07-30 19:30 被阅读17次

    Manifest文件权限配置说明

    使用蓝牙,扫描蓝牙和设置蓝牙设置需要用到

    <uses-permission android:name="android.permission.BLUETOOTH"/>

    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>

    Android 5.0以上需要额外配置位置权限

    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>

    <uses-permission android:name="andriod.permission.ACCESS_FINE_LOCATION"/>

    注意ACCESS_COARSE_LOCATION权限在6.0上需要动态获取,否则无法搜索出设备

    <uses-feature android:name="android.bluetooth.le" android:required="true"/> 
    

    这个权限是为了区分不支持BLE的android设备无法运行该APP,required=true,只能在支持BLE的android设备上安装运行该APP,required=false,所有设备均可以运行
    这个权限贴出来只作了解,具体使用还是在代码中判断设备是否支持BLE作逻辑结束比较好

    if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
    
       Log.e("yzh","不支持BLE功能")
    
       finish();
    
    }
    

    蓝牙的交互流程

    1.开启手机蓝牙模块搜索蓝牙信号

    2.根绝device的uuid,name或者address找到需要连接设备

    3.进行通道连接,遍历所有的通道中的服务,再遍历每个服务中的特征值

    4.找到需要用的特征值进行读写操作

    初始化蓝牙管理对象

    BluetoothManager bluetoothManager=(BluetoothManager)getSystemService(Context.BLUETOOTH_SERVICE);
    BluetoothAdapter bluetoothAdapter=bluetoothManager.getAdapter();
    

    判断蓝牙功能是否开启,未开始默认开始

    if(bluetoothAdapter==null||!bluetoothAdapter.isEnabled()){
            bluetoothAdapter.enable();
        }
    

    蓝牙搜索

    bluetoothAdapter.getBluetoothLeScanner().startScan(callback);
    
    private ScanCallback callback =new ScanCallback() {
        @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
        @Override
        public void onScanResult(int callbackType, ScanResult result) {
            if(!list.contains(result.getDevice())){
                Log.e("yzh","onScanResult--"+result.getDevice().getUuids()+"--"+result.getDevice().getAddress()+"--"+result.getDevice().getName());
                list.add(result.getDevice());
            }
        }
    
        @Override
        public void onBatchScanResults(List<ScanResult> results) {
            Log.e("yzh","onBatchscanresult");
        }
    
        @Override
        public void onScanFailed(int errorCode) {
            Log.e("yzh","onScanFailed"+errorCode);
        }
    };
    

    startScan(List<ScanFilter> filters, ScanSettings settings, ScanCallback callback),上面搜索方法还可以带两个参数,筛选搜索结果

     public List<ScanFilter> getScanFilters(String[] uuids){
        List<ScanFilter> filters=new ArrayList<>();
        if(uuids!=null&&uuids.length>0){
            for (String s:uuids){
                ScanFilter.Builder  builder1=new ScanFilter.Builder();
                builder1.setServiceUuid(ParcelUuid.fromString(s));
                // builder1.setDeviceName("QN-Scale");
                ScanFilter filter=builder1.build();
                filters.add(filter);
            }
        }
        return filters;
    }
    public ScanSettings getScanSettings(int times){
        ScanSettings.Builder builder = new ScanSettings.Builder();
        builder.setReportDelay(times);
        builder.setScanMode(ScanSettings.SCAN_MODE_BALANCED);
        // builder.setMatchMode(ScanSettings.MATCH_NUM_ONE_ADVERTISEMENT);
        ScanSettings settings=builder.build();
        return settings;
    }
    

    这里发现以前的搜索方法被废弃了,查阅是5.0以上新增api之后。网上介绍蓝牙ble的文章相对较少,很多以前的代码都会使用这2个方法,在这里贴出来说明一下

    bluetooth.startLeScan;
    bluetooth.stopLeScan;
    

    连接蓝牙

    //关闭蓝牙扫描 防止阻塞
    bluetoothAdapter.getBluetoothLeScanner().stopScan(callback);
    //通过蓝牙地址获取蓝牙设备
    device=bluetoothAdapter.getRemoteDevice("F4:51:41:55:04:FC");
    //设备建立通道连接
    bluetoothGatt=device.connectGatt(BleConnectActivity.this,false,bleGattCallback);
    
    //连接回调
    private BluetoothGattCallback bleGattCallback =new BluetoothGattCallback() {
        @Override
        public void onPhyUpdate(BluetoothGatt gatt, int txPhy, int rxPhy, int status) {
            super.onPhyUpdate(gatt, txPhy, rxPhy, status);
        }
    
        @Override
        public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
            super.onConnectionStateChange(gatt, status, newState);
            Log.e("yzh", "onConnectionStateChange"+"--status="+status);
    
            if (newState == BluetoothProfile.STATE_CONNECTED) {
                Log.e("yzh", "连接成功");
                //连接成功之后扫描服务
                gatt.discoverServices();
            } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
                if(status==0){
                    gatt.connect();
                }else{
                    //尝试重连的代码
                    gatt.disconnect();
                    gatt.close();
                    device.connectGatt(BleConnectActivity.this,false,bleGattCallback);
    
                }
                Log.e("yzh", "断开");
            }
    
        }
    
        @Override
        public void onServicesDiscovered(BluetoothGatt gatt, int status) {
            super.onServicesDiscovered(gatt, status);
            Log.e("yzh", "onServicesDiscovered");
            String uuid = null;
            if (status == BluetoothGatt.GATT_SUCCESS) {
                //读取服务和每个服务下对应的特征值
                List<BluetoothGattService> gattServices = gatt.getServices();
                for (BluetoothGattService gattService : gattServices) {
                    uuid = gattService.getUuid().toString();
                    Log.e("yzh", "serviceUUid--" + uuid);
                    List<BluetoothGattCharacteristic> gattCharacteristics = gattService.getCharacteristics();
                    for (BluetoothGattCharacteristic gattCharacteristic : gattCharacteristics) {
                        uuid = gattCharacteristic.getUuid().toString();
                        Log.e("yzh", "characteristic--" + uuid+"--"+gattCharacteristic.getProperties());
                    }
                }
            }
        }
    
        @Override
        public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
            super.onCharacteristicRead(gatt, characteristic, status);
            Log.e("yzh", "onCharacteristicRead");
            if (status == BluetoothGatt.GATT_SUCCESS) {
                //读取特征值携带的信息  下面用了很多方式来解读返回的byte数组 实际要与硬件方沟通对接
                String uuid = null;
                uuid = characteristic.getUuid().toString();
                Log.e("yzh","--uid--"+uuid);
                try{
                Log.e("yzh","--value--"+bytesToHexString(characteristic.getValue()));
                Log.e("yzh","GBKvalue"+ new String(characteristic.getValue(),"GBK").toString());
                    Log.e("yzh","UTF-8value"+ new String(characteristic.getValue(),"UTF-8").toString());
                    Log.e("yzh","unicode-8value"+ new String(characteristic.getValue(),"unicode").toString());
                    Log.e("yzh","ISO8859-1-8value"+ new String(characteristic.getValue(),"ISO8859-1").toString());
                    Log.e("yzh","base64value"+  android.util.Base64.encodeToString(characteristic.getValue(), android.util.Base64.DEFAULT));
                }catch (Exception e){
                }
    
          
                    final byte[] data = characteristic.getValue();
    
    
                    for(int i=0;i<data.length;i++){
                        Log.e("yzh", "detailValue--"+data[i] + "--");
                    }
            }
        }
    
        @Override
        public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
            super.onCharacteristicChanged(gatt, characteristic);
        }
    };
    

    注意:这里有几点存在疑问或者说没有找到最优解

    1.connectGatt()方法第二个参数的解读是在蓝牙断开,会进行自动重连,但是在验证过程中并没有重连的现象

    2.onConnectionStateChange方法里写的重连方法,在验证时一直无法重连,返回状态值133,gatt.disconnect,gatt.close是网上找的一些建议,但并未生效,找到一个有效方式是先开启搜索再连接,网上也有人是这样做的,最好用不同的硬件和不同的手机系统去验证这个问题。

    蓝牙数据读取

    bluetoothGatt.readCharacteristic(characteristic);
    
    //在回调方法里面接受特征值里面的数据
    onCharacteristicRead
    

    蓝牙数据写入

    characteristic.setValue()//传入需要写入的数据
    bluetoothGatt.writeCharacteristic(characteristic);//往设备写入数据
    //开启 Android 端接收通知的开关
    mBluetoothGatt.setCharacteristicNotification(characteristic, enabled);
    //CLIENT_CHARACTERISTIC_CONFIG = "00002902-0000-1000-8000-00805f9b34fb"
    //characteristic的Descriptor属性写入开启通知的数据,保证硬件数据变化时,主动往手机发送数据
     BluetoothGattDescriptor descriptor = characteristic.getDescriptor( UUID.fromString(SampleGattAttributes.CLIENT_CHARACTERISTIC_CONFIG)); descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE); mBluetoothGatt.writeDescriptor(descriptor); 
    

    监听写入成功

     @Override
        public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
            super.onCharacteristicWrite(gatt, characteristic, status);
        }
    

    监听写入数据之后数据的返回通知

    @Override
        public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
            super.onCharacteristicChanged(gatt, characteristic);
        }
    

    相关文章

      网友评论

        本文标题:Android蓝牙BLE入门

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