2017-01-24 9 views
1

Я пытаюсь сделать приложение Android, которое может рекламировать кадры UID на основе протокола Eddystone. Код для которого следующий:Рекламные данные слишком большие Eddystone Beacon

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

Что я здесь отсутствует?

ответ

0

Я подозреваю, что проблема заключается в том, что сервис uuid, который вы вставляете в рекламу, заканчивается тем, что является полным 16-байтным Service UUID вместо требуемого 2-байтного короткого Service UUID 0xFEAA. Недостаточно места для полного 16-байтного Service 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)); 
} 
+0

Спасибо за ваше ценное понимание. Поправьте меня, если я ошибаюсь. В соответствии с тем, что вы упомянули, сгенерированный UUID слишком длинный, чтобы его можно было установить как служебный UUID. Вместо этого метод, который вы упомянули, предоставит требуемый UUID службы обслуживания? Код, который я написал, был основан на Google Eddystone repo на git: [link] (https://github.com/google/eddystone/blob/master/eddystone-uid/tools/txeddystone-uid/TxEddystone-UID/app/ src/main/java/com/google/sample/txeddystone_uid/MainActivity.java) Будучи новичком, мне показалось странным, что об этом нет упоминания. Это то, что понимается по умолчанию? –

+0

Интересно, да, я вижу, что это в ссылочном коде. Возможно, некоторые версии Android неправильно анализируют это как двухбайтовый UUID: 'ParcelUuid.fromString (« 0000FEAA-0000-1000-8000-00805F9B34FB »);' – davidgyoung

+0

Ваше решение работает по мере необходимости. Я больше не сталкиваюсь с этим вопросом. Спасибо –

0

К сожалению, я не могу добавить комментарий, чтобы опубликовать это как ответ. Извините ...

Как выглядит метод toByteArray?

Вы регистрируете много информации, можете ли вы добавить также зарегистрированные значения?

(кстати, не уверен, есть ли у вас понятие TAG и е, ж, д, ... методы класса Log. Я рекомендую пересмотреть свой подход протоколирования ...)

+0

Благодарим за ответ. У меня есть метод toByteArray. Также я использую LOG только для получения значений на данный момент; Обычно я употребляю тосты. Это не будет в конечном коде. Это то, что я нашел из LOG: 'Пространство имен: 10bytes Идентификатор экземпляра: 6bytes и служебные данные: 18bytes' Пространство имен и длина экземпляра, как рекомендуется. Что, по-вашему, вызывает проблему? –

+0

Я бы сосредоточился на @davidgyoung намеке о длине службы UUID ... – Dietatko