如何通过scanRecord识别Eddystone

Ste*_*des 3 android bluetooth gatt

我正在开发一款正在扫描BLE设备的Android应用程序.每当我找到一台设备时,我都会收到: byte[] scanRecord, BluetoothDevice device, int rssi来自 BluetoothAdapter.startLeScan()

然后我将字节数组转换为ScanRecord对象: ScanRecord.parseFromBytes()

我现在从我的Eddystone(来自toString()方法)获得以下信息.

`com.reelyactive.blesdk.support.ble.ScanRecord [mAdvertiseFlags=6, mServiceUuids=[0000feaa-0000-1000-8000-00805f9b34fb], mManufacturerSpecificData={}, mServiceData={0000feaa-0000-1000-8000-00805f9b34fb=[16, -36, 2, 107, 110, 116, 107, 46, 105, 111, 47, 101, 100, 100, 121, 115, 116, 111, 110, 101], 0000d00d-0000-1000-8000-00805f9b34fb=[67, 77, 103, 52, 50, 57, 100]}, mTxPowerLevel=-12, mDeviceName=IIS_EDDY_003] IIS_EDDY_003` 
Run Code Online (Sandbox Code Playgroud)

有人能告诉我,如何使用此信息将设备识别为Eddystone?服务uuid​​s可能吗?我并不总是知道设备的名称或地址.

Tak*_*aki 5

android.bluetooth.le.ScanRecord 是Android中最糟糕的API之一.

如果您已经有scanRecord(字节数组),我建议使用nv-bluetooth来提取Eddystone数据.以下代码段显示了nv-bluetooth的用法.

// Parse the payload of the advertising packet.
List<ADStructure> structures =
    ADPayloadParser.getInstance().parse(scanRecord);

// For each AD structure contained in the payload.
for (ADStructure structure : structures)
{
    if (structure instanceof EddystoneUID)
    {
        // Eddystone UID
        EddystoneUID es = (EddystoneUID)structure;

        // (1) Calibrated Tx power at 0 m.
        int power = es.getTxPower();

        // (2) 10-byte Namespace ID
        byte[] namespaceId = es.getNamespaceId();
        String namespaceIdAsString = es.getNamespaceIdAsString();

        // (3) 6-byte Instance ID
        byte[] instanceId = es.getInstanceId();
        String instanceIdAsString = es.getInstanceIdAsString();

        // (4) 16-byte Beacon ID
        byte[] beaconId = es.getBeaconId();
        String beaconIdAsString = es.getBeaconIdAsString();
    }
    else if (structure instanceof EddystoneURL)
    {
        // Eddystone URL
        EddystoneURL es = (EddystoneURL)structure;

        // (1) Calibrated Tx power at 0 m.
        int power = es.getTxPower();

        // (2) URL
        URL url = es.getURL();
    }
    else if (structure instanceof EddystoneTLM)
    {
        // Eddystone TLM
        EddystoneTLM es = (EddystoneTLM)structure;

        // (1) TLM Version
        int version = es.getTLMVersion();

        // (2) Battery Voltage
        int voltage = es.getBatteryVoltage();

        // (3) Beacon Temperature
        float temperature = es.getBeaconTemperature();

        // (4) Advertisement count since power-on or reboot.
        long count = es.getAdvertisementCount();

        // (5) Elapsed time in milliseconds since power-on or reboot.
        long elapsed = es.getElapsedTime();
    }
    else if (structure instanceof IBeacon)
    {
        // iBeacon
        IBeacon iBeacon = (IBeacon)structure;

        // (1) Proximity UUID
        UUID uuid = iBeacon.getUUID();

        // (2) Major number
        int major = iBeacon.getMajor();

        // (3) Minor number
        int minor = iBeacon.getMinor();

        // (4) Tx Power
        int power = iBeacon.getPower();
    }
}
Run Code Online (Sandbox Code Playgroud)

上面的代码暗示应该将扫描记录解析为AD结构列表.然而,parseFromBytesandroid.bluetooth.le.ScanRecord不解析以正确的方式扫描记录.

ScanRecord 有以下方法(和其他一些方法):

  1. getAdvertiseFlags()
  2. getDeviceName()
  3. getManufacturerSpecificData()
  4. getServiceData()
  5. getTxPowerLevel()

这些方法对应于一些AD结构.此API设计与AnimalRecord下面显示的类相同.

public class AnimalRecord
{
    public Cat getCat() { ... }
    public Dog getDog() { ... }
    public Eagle getEagle() { ... }
    ...
}
Run Code Online (Sandbox Code Playgroud)

标志,本地名称,制造商特定数据,服务数据和Tx功率级别也应解析为AD结构,如下所示.

// Parse the payload of the advertising packet.
List<ADStructure> structures =
    ADPayloadParser.getInstance().parse(scanRecord);

// For each AD structure contained in the payload.
for (ADStructure structure : structures)
{
    if (structure instanceof Flags)
    {
        // Flags
        Flags flags = (Flags)structure;
    }
    else if (structure instanceof LocalName)
    {
        // Local Name
        LocalName name = (LocalName)structure;
    }
    else if (structure instanceof ADManufacturerSpecific)
    {
        // Manufacturer Specific Data
        // Note that iBeacon is a kind of Manufacturer Specific Data
        ADManufacturerSpecific ms = (ADManufacturerSpecific)structure;
    }
    else if (structure instanceof ServiceData)
    {
        // Service Data
        // Note that Eddystone is a kind of Service Data.
        ServiceData sd = (ServiceData)structure;
    }
    else if (structure instanceof TxPowerLevel)
    {
        // TxPowerLevel
        TxPowerLevel level = (TxPowerLevel)structure;
    }
}
Run Code Online (Sandbox Code Playgroud)

如上面的代码所述,Eddystone是一种服务数据.因此,Eddystone UID,Eddystone URL和Eddystone TLM应该具有如下所示的继承树.

ADStructure
  |
  +-- ServiceData
        |
        +-- Eddystone
              |
              +-- EddystoneUID
              +-- EddystoneURL
              +-- EddystoneTLM
Run Code Online (Sandbox Code Playgroud)

我希望那些非常了解BLE规范并具备良好设计技能的人将从头开始重写Android的BLE API.