广告数据太大 Eddystone Beacon

Advertised Data too Large Eddystone Beacon

我正在尝试制作一个 android 应用程序,该应用程序能够基于 Eddystone 协议发布 UID 帧。其代码如下

private void advertise() {
    //To check if Bluetooth Multiple Advertising is supported on the Device
    if( !BluetoothAdapter.getDefaultAdapter().isMultipleAdvertisementSupported() ) {
        Toast.makeText( this, "Multiple advertisement not supported", Toast.LENGTH_SHORT ).show();
        start.setEnabled(false);
    }

    BluetoothLeAdvertiser advertiser = BluetoothAdapter.getDefaultAdapter().getBluetoothLeAdvertiser();
    //defining the settings used while advertising
    AdvertiseSettings settings = new AdvertiseSettings.Builder().setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_BALANCED).setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_HIGH).setConnectable(true).build();

    //We make Parcel UUID(UUID can be generated online) and Advertise Data object
    ParcelUuid pUuid = ParcelUuid.fromString("4db3d4ff-eda4-46e8-bd89-9a7b1f63cc83");

    //building servicedata
    byte txPower = (byte) -16;
    byte FrameType = 0x00;
    byte[] namespaceBytes =toByteArray("01020304050607080910");
    Log.e("nB",Integer.toString(namespaceBytes.length));
    byte[] instanceBytes =toByteArray("AABBCCDDEEFF");
    Log.e("instanceIdlength",Integer.toString(instanceBytes.length));
    ByteArrayOutputStream os = new ByteArrayOutputStream();
    try {
        os.write(new byte[]{FrameType,txPower});
        os.write(namespaceBytes);
        os.write(instanceBytes);
    } catch (IOException e) {
        e.printStackTrace();
    }

    byte[] serviceData =os.toByteArray();
    Log.e("Service Data Length",Integer.toString(serviceData.length));
    Log.e("ServiceData",serviceData.toString());

    AdvertiseData ADdata = new AdvertiseData.Builder().addServiceData(pUuid,serviceData).addServiceUuid(pUuid).setIncludeDeviceName(false).setIncludeTxPowerLevel(false).build();

    Log.e("Data",ADdata.toString());




     //callback to check success or failure when advertising
    AdvertiseCallback advertisingCallback = new AdvertiseCallback() {
        @Override
        public void onStartSuccess(AdvertiseSettings settingsInEffect) {
            super.onStartSuccess(settingsInEffect);
            Log.e("BLE","Advertising");
            status.setText("Advertising");
            status.setTextColor(Color.GREEN);
            }
        @Override
        public void onStartFailure(int errorCode) {
            Log.e( "BLE", "Advertising onStartFailure: " + errorCode );
            super.onStartFailure(errorCode);
            status.setText("ErrorCode: "+errorCode);
            status.setTextColor(Color.RED);
            }
    };

    advertiser.startAdvertising(settings, ADdata, advertisingCallback);
}

private byte[] toByteArray(String hexString) {
// hexString guaranteed valid.
int len = hexString.length();
byte[] bytes = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
  bytes[i / 2] = (byte) ((Character.digit(hexString.charAt(i), 16) << 4)
      + Character.digit(hexString.charAt(i + 1), 16));
}
return bytes;}

我已遵守帧长度的所有准则。

InstanceID:6bytes
NameSpaceID:10bytes

但由于错误代码,我仍然无法发布数据.... :ADVERTISE_FAILED_DATA_TOO_LARGE

这里有什么我遗漏的吗?

我怀疑问题是您在广告中插入的服务 uuid 最终是一个完整的 16 字节服务 UUID,而不是所需的 0xFEAA 的 2 字节短服务 UUID。没有足够的空间容纳完整的 16 字节服务 UUID,这就是您收到此错误的原因。

我在构建 Eddystone transmission support in the Android Beacon Library 时遇到了一些困难,最终从 AOSP 复制了一个函数,如下所示。您可以在下面的库中看到它是如何使用的。

int serviceUuid = 0xFEAA;
byte[] serviceUuidBytes = new byte[] {
   (byte) (serviceUuid & 0xff),
   (byte) ((serviceUuid >> 8) & 0xff)};
ParcelUuid parcelUuid = parseUuidFrom(serviceUuidBytes);


/**
 * Parse UUID from bytes. The {@code uuidBytes} can represent a 16-bit, 32-bit or 128-bit UUID,
 * but the returned UUID is always in 128-bit format.
 * Note UUID is little endian in Bluetooth.
 *
 * @param uuidBytes Byte representation of uuid.
 * @return {@link ParcelUuid} parsed from bytes.
 * @throws IllegalArgumentException If the {@code uuidBytes} cannot be parsed.
 *
 * Copied from java/android/bluetooth/BluetoothUuid.java
 * Copyright (C) 2009 The Android Open Source Project
 * Licensed under the Apache License, Version 2.0
 */
private static ParcelUuid parseUuidFrom(byte[] uuidBytes) {
    /** Length of bytes for 16 bit UUID */
    final int UUID_BYTES_16_BIT = 2;
    /** Length of bytes for 32 bit UUID */
    final int UUID_BYTES_32_BIT = 4;
    /** Length of bytes for 128 bit UUID */
    final int UUID_BYTES_128_BIT = 16;
    final ParcelUuid BASE_UUID =
            ParcelUuid.fromString("00000000-0000-1000-8000-00805F9B34FB");
    if (uuidBytes == null) {
        throw new IllegalArgumentException("uuidBytes cannot be null");
    }
    int length = uuidBytes.length;
    if (length != UUID_BYTES_16_BIT && length != UUID_BYTES_32_BIT &&
            length != UUID_BYTES_128_BIT) {
        throw new IllegalArgumentException("uuidBytes length invalid - " + length);
    }
    // Construct a 128 bit UUID.
    if (length == UUID_BYTES_128_BIT) {
        ByteBuffer buf = ByteBuffer.wrap(uuidBytes).order(ByteOrder.LITTLE_ENDIAN);
        long msb = buf.getLong(8);
        long lsb = buf.getLong(0);
        return new ParcelUuid(new UUID(msb, lsb));
    }
    // For 16 bit and 32 bit UUID we need to convert them to 128 bit value.
    // 128_bit_value = uuid * 2^96 + BASE_UUID
    long shortUuid;
    if (length == UUID_BYTES_16_BIT) {
        shortUuid = uuidBytes[0] & 0xFF;
        shortUuid += (uuidBytes[1] & 0xFF) << 8;
    } else {
        shortUuid = uuidBytes[0] & 0xFF ;
        shortUuid += (uuidBytes[1] & 0xFF) << 8;
        shortUuid += (uuidBytes[2] & 0xFF) << 16;
        shortUuid += (uuidBytes[3] & 0xFF) << 24;
    }
    long msb = BASE_UUID.getUuid().getMostSignificantBits() + (shortUuid << 32);
    long lsb = BASE_UUID.getUuid().getLeastSignificantBits();
    return new ParcelUuid(new UUID(msb, lsb));
}