广告数据太大 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));
}
我正在尝试制作一个 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));
}