Android BLE 广播定制

Posted 为往圣而继绝学

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android BLE 广播定制相关的知识,希望对你有一定的参考价值。

近期项目中用到蓝牙BLE,需要区分设备及显示蓝牙名。对于蓝牙BLE广播,发送字节数超过31会广播失败(原因之一是蓝牙名称太长),再者蓝牙mac地址是动态的无法区分设备。和同事交流后,采用他的项目中的方法。

名称太长问题

  1. 广播时,不添加Service UUID,采用2个字节表示服务。
  2. 蓝牙名字符长度超过10则截取前十个字符,并发送表示名称不完整的字节。

设备唯一性

随机两个数字保存在本地,广播时作为设备码(占用2个字节)发送。

代码实现

广播数据部分

    private AdvertiseData buildAdvertiseData(boolean includeDeviceName) 
        
        SharedPreferences sharedPreferences = mContext.getSharedPreferences("config_ble", Context.MODE_PRIVATE);
        int key1 = sharedPreferences.getInt("key1", 0);
        int key2 = sharedPreferences.getInt("key2", 0);
        if (key1 == 0 || key2 == 0) 
            Random random = new Random();
            key1 = 10 + random.nextInt(89);
            key2 = 10 + random.nextInt(89);
            sharedPreferences.edit().putInt("key1", key1).putInt("key2", key2).apply();
        
        String name = mBluetoothAdapter.getName();
        boolean isFullName = true;
        int maxNameLength = 10;
        if (TextUtils.isEmpty(name)) 
            name = String.format("BLE-%s%s", key1, key2);
         else 
            if (name.length() > maxNameLength) 
                name = name.substring(0, maxNameLength);
                isFullName = false;
            
        
        byte[] bytes = name.getBytes(StandardCharsets.UTF_8);
        byte[] nameBytes = new byte[bytes.length + 1];
        nameBytes[0] = (byte) (isFullName ? 1 : 0);
        System.arraycopy(bytes, 0, nameBytes, 1, bytes.length);
        String realName = isFullName ? name : (name + "...");
        return
                new AdvertiseData.Builder()
                .setIncludeDeviceName(false) //包含蓝牙名称,不能传送名字(太长超过31字节),会广播不成功
                .addManufacturerData(0, new byte[]0x6A, 0x7E) //标识该服务
                .addManufacturerData(1, new byte[](byte) key1, (byte) key2)//设备码
                .addManufacturerData(2, nameBytes)//蓝牙名
                .build();
    

蓝牙扫描过滤

    private fun buildScanFilter(): List<ScanFilter> 
        val scanFilters = ArrayList<ScanFilter>()
        val filter = ScanFilter.Builder()
            .setManufacturerData(0, new byte[]0x6A, 0x7E)
            .build()
        scanFilters.add(filter)
        return scanFilters
    

蓝牙数据ScanResult解析

        val scanRecord = scanResult?.scanRecord
        val deviceCode: Int =
            scanRecord?.getManufacturerSpecificData(1)?.let  100 * it[0] + it[1]  ?: 0
        val deviceName = scanRecord?.getManufacturerSpecificData(2)?.let  bytes ->
            val name = String(bytes.sliceArray(1 until bytes.size))
            if (bytes[0].toInt() == 0) 
                "$name..."
             else 
                name
            
         ?: "null"

以上是关于Android BLE 广播定制的主要内容,如果未能解决你的问题,请参考以下文章

android BLE Peripheral 手机模拟设备发出BLE广播 BluetoothLeAdvertiser

android蓝牙BLE(三) —— 广播

Android 如何像在 iOS 中一样广播 BLE 本地名称?

android BLE Peripheral 做外设模拟设备,供iosandroid 连接通讯。

BLE iOS Nativescript:广播数据失败

杂记:解决Android扫描BLE设备名称不刷新问题