Android蓝牙BLE入门

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);
    }
    原文作者:tmyzh
    原文地址: https://www.jianshu.com/p/7a25c3eda652
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞