蓝牙开发遇到几个问题

1.有些手机无法搜索的设备名
public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) {
//有些手机扫描不到设备名称,只有在scanRecord里才有这些名字信息  test假定是我们关键字,然后我们名称是固定长度就可以截取出来了
String tmpName=new String(scanRecord);
LOG.i(TAG, "scanRecord 里的值:"+tmpName );
if(tmpName.contains("test")){
try {
String deviceName=tmpName.substring(tmpName.indexOf("test"),tmpName.indexOf("test")+13);
}catch (Exception e){
e.printStackTrace();
}
}
}


2. 6.0以上的蓝牙手机需要开启定位可以搜索到设备
权限ACCESS_COARSE_LOCATION


3.手机蓝牙在打开的时候可能是在自己搜索蓝牙设备,导致我们第一次去搜索蓝牙设备都搜不到,这个我时候我采用
首先如果蓝牙没打开,就先打开蓝牙
延迟两秒再执行
mBluetoothAdapter.stopLeScan(callback);

mBluetoothAdapter.startLeScan(callback);

 

4. vivo  X20A还必须得有

android.permission.BLUETOOTH_PRIVILEGED  

5.0以上系统静默开启蓝牙需要这个操作,不然会出现E/BluetoothAdapter: startLeScan: cannot get BluetoothLeScanner

 

5.华为荣耀3c 手机 蓝牙连接  出现过一次   搜索不到蓝牙设备,厂商提供搜索工具也搜索不到,其他手机打开蓝牙可以搜索到该设备,打开蓝牙开发检测后就可以了,再关闭蓝牙检测也可以,再也无法复现了

 

6.打开蓝牙三种方式

隐形打开(在5.0以上需要支持android.permission.BLUETOOTH_PRIVILEGED  有些手机比如Vivo拒绝后可能一直打开不了)

而且大部分手机如果隐式打开,还是会提示,所以还不如干脆直接显式打开,兼容性会更好

BluetoothManager mBluetoothManager = (BluetoothManager) context.getSystemService(Context.BLUETOOTH_SERVICE);
BluetoothAdapter mBluetoothAdapter = mBluetoothManager.getAdapter();
mBluetoothAdapter.enable();

显性打开(最好是在UI里有做提示用户来打开,这样对用户和兼容性比较好,太多自定义系统在权限那块兼容不太好)

//会弹出系统对话框,提示用户是否允许蓝牙设备对其他设备的可见性
Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
intent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 120);//可被发现的持续时间
startActivity(intent);

//会弹出一个对话框,提示用户是否允许打开蓝牙
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivity(enableBtIntent);

//打开系统蓝牙界面
Intent intent = new Intent(Settings.ACTION_BLUETOOTH_SETTINGS);
startActivity(intent);

7.蓝牙通讯联调

每次底层发送数据如果超过20个字节,或者是每20个字节发送间隔少于40ms(预估时间,如果还是容易蓝牙死掉,那么时间就需要延长)可能导致蓝牙死掉,Android收不到或者蓝牙设备的嵌入式死掉

 

8.蓝牙联调工具 

https://download.csdn.net/download/z157794218/11777902     想改积分,但是改不了,也可以自行百度

Android是nRF connect.apk          IOS是lightBlue

9.关于设置蓝牙mtu 大小

1)首先最大可设置成512(Android5.1上才支持)  

2)我们使用indications方式,需要先enable的CCCD特征值

protected final boolean enableIndications(final BluetoothGattCharacteristic characteristic) {
    final BluetoothGatt gatt = mBluetoothGatt;
    if (gatt == null || characteristic == null)
        return false;

    // Check characteristic property
    final int properties = characteristic.getProperties();
    if ((properties & BluetoothGattCharacteristic.PROPERTY_INDICATE) == 0)
        return false;

    boolean isEnableSuccess= gatt.setCharacteristicNotification(characteristic, true);
    final BluetoothGattDescriptor descriptor = characteristic.getDescriptor(UUID.fromString(mConfig.getUuidCccd()));
    if (descriptor != null) {
        boolean isSetValueSuccess=descriptor.setValue(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE);
        return gatt.writeDescriptor(descriptor);
    }
    return false;
}

3)然后间隔500ms再调用修改mtu大小

public static void exchangeGattMtu(BluetoothGatt gatt,int mtu) {
    int retry = 5;
    boolean status = false;
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
        while ((false == status) && retry > 0) {
            status = gatt.requestMtu(mtu);//这个是设置  我尝试过如果只设置一次,可能会设置不成功没有回调
            retry--;
        }
    }
}

4)蓝牙服务设置成功后会回调

BluetoothGattCallback里onMtuChanged方法,告知实际上设置成功mtu的大小,你发送最大只能用这个去发送,超过也会发送不过去

5)关于MTU有个最坑的,坑了我几天的问题,下面重点(不要无缝操作蓝牙,一定需要有间隔时间)

在调用改变mtu大小前,请先将蓝牙读的特征值CCCD最好是enable(即2步骤),否则可能导致设置也无效,并且在读特征值enable和改变mtu大小之间一定要间隔500ms左右,不间隔看到设置成功也发送不了和接收不了数据

enableIndications(characteristic);
try {
    Thread.sleep(500);
} catch (InterruptedException e) {
    e.printStackTrace();
}
exchangeGattMtu(gatt,512);

6)参考https://blog.csdn.net/make_progress/article/details/86551379

a.蓝牙MTU默认23个Byte(20个用于通讯,3个标志位)

core spec中ATT的默认MTU为23个Byte,ATT的Opcode占1个Byte、ATT的Handle2个Byte、GATT占20个Byte。
23Byte(ATT)=1Byte(Opcode)+2Byte(Handler)+20Byte(BATT)

b.不同的蓝牙版本最大MTU不同,例如:蓝牙4.2的最大MTU=247Byte(不一定正确,也有说是257Byte、也有说是241Byte),蓝牙5.0的最大MTU=512,有效的最大MTU还需要减去协议Byte、Opcode和Handler。蓝牙4.2的有效的最大MTU是244Byte(不一定正确),有兴趣的可以看看Bluetooth SIG官网https://bluetoothworldevent.com/welcome。
蓝牙4.2:1Byte(Opcode)+2Byte(Handler)+244Byte(BATT)=247Byte(不一定正确);
蓝牙5.0:没查到

蓝牙4.1和4.0是不支持大包模式,最好还是按23个mtu处理

 

 

10.ENABLE_NOTIFICATION_VALUE  这种方式类似网络中udp,丢过去就好了,不管成功与否
ENABLE_INDICATION_VALUE    这种方式类似网络的tcp(丢过去就会有回应ACK)

两者区别只是通过设置读特征值的CCCD客户端配置描述设置,因为其实底层都是广播的socket没有实际区别,只是系统蓝牙在上面做了一下所谓的ack的区别

descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
descriptor.setValue(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE);

 

11.蓝牙的处理不过来系统处理不过来拒收问题

public static boolean isDeviceBusy(BluetoothGatt mBluetoothGatt) {
    boolean state = false;
    try {
        state = (boolean) readField(mBluetoothGatt, "mDeviceBusy");
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    } catch (NoSuchFieldException e) {
        e.printStackTrace();
    }
    return state;
}

public static Object readField(Object object, String name) throws IllegalAccessException, NoSuchFieldException {
    Field field = object.getClass().getDeclaredField(name);
    field.setAccessible(true);
    return field.get(object);
}

参考:https://blog.csdn.net/pan0755/article/details/107865725

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值