androidbluetooth-lowenergyeddystoneeddystone-url

Eddystone-url set or disable expansion


I'm writing an Eddystone-url BLE advertiser for android. However I have problems with encoding the url correctly. According to the specifications (https://github.com/google/eddystone/tree/master/eddystone-url), the scheme prefix (e.g. http://www.) can be set with a single byte (e.g. 0x00). The same is supposed to happen at the expansion (e.g. .com/ = 0x00). There is a whole list for different prefixes and expansions.

While the prefix is working, the expansion behaves strangely.

If I enter:

url = "http://www.orf.at/"

a BLE scanner retrieves exactly this url.

If I enter:

url = "http://www.orf.at"

without the "/" at the end, the BLE scanner tells me that a ".com" is added like:

"http://www.orf.at.com"

If I enter:

url = "http://www.orf.at/test"

The retrieved url looks like the original again.

How do I use the expansion encoding? Or how can I disable it? It seems to be very unreliable.

My according code:

 private AdvertiseData buildEddystoneURLData(String url) throws UnsupportedEncodingException {
    ByteArrayOutputStream os = new ByteArrayOutputStream();

    //frame type
    os.write((byte) 0x10);
    //TX Power
    os.write((byte) 0xB5);

    //URL scheme code
    /*
    0   0x00    http://www.
    1   0x01    https://www.
    2   0x02    http://
    3   0x03    https://
    */
    if(url.startsWith("http://www.")){
        os.write((byte) 0x00);
        url = url.substring(11,url.length());
        log("starts with http://www.");
        log("cutting to: "+url);
    }else if(url.startsWith("https://www.")){
        os.write((byte) 0x01);
        url = url.substring(12,url.length());
        log("starts with https://www.");
        log("cutting to: "+url);
    }
    else if(url.startsWith("http://")){
        os.write((byte) 0x02);
        url = url.substring(7,url.length());
        log("starts with http://");
        log("cutting to: "+url);
    }
    else if(url.startsWith("https://")){
        os.write((byte) 0x03);
        url = url.substring(8,url.length());
        log("starts with https://");
        log("cutting to: "+url);
    }

    byte [] advertiseBytes = string2byte(url);
    //0-17: url
    for (Byte bt: advertiseBytes) {
        os.write(bt);
    }

    byte[] serviceData = os.toByteArray();

    ParcelUuid SERVICE_UUID = ParcelUuid.fromString("0000FEAA-0000-1000-8000-00805F9B34FB");
    AdvertiseData.Builder builder = new AdvertiseData.Builder();
    if(serviceData!=null) {
        builder.addServiceData(SERVICE_UUID, serviceData)
                .addServiceUuid(SERVICE_UUID)
                .setIncludeTxPowerLevel(false)
                .setIncludeDeviceName(false);   //don't include device name - it does not work

        return builder.build();
    }
    else
        return  null;
}

Update string2byte:

private byte[] string2byte(String st) throws UnsupportedEncodingException {
    return st.getBytes("UTF-8");
}

And printing the bytes in logcat shows this: for "http://www.orf.at/":

starts with http://www.
cutting to: orf.at/
getServiceData at: 0000feaa-0000-1000-8000-00805f9b34fb
byte: 16
byte: -75
byte: 0
byte: 111
byte: 114
byte: 102
byte: 46
byte: 97
byte: 116
byte: 47
getServiceData as String: ���orf.at/

And this for: "http://www.orf.at":

starts with http://www.
cutting to: orf.at
getServiceData at: 0000feaa-0000-1000-8000-00805f9b34fb
byte: 16
byte: -75
byte: 0
byte: 111
byte: 114
byte: 102
byte: 46
byte: 97
byte: 116
getServiceData as String: ���orf.at

Solution

  • You cannot disable expansion -- it is part of the spec. Receivers will expand any bytes that match expansion patterns. So you need to ensure that any bytes transmitted do not inadvertently contain expansion bytes.

    I suspect there is a bug in the string2byte function which is adding an extra 0 byte at the end of "http://www.orf.at" when converting it to bytes. This would cause the symptoms you see.

    If you post the definition of this function and a logged output of the actual bytes put into the output stream, this may help diagnose the problem.

    EDIT: Alternatively, it is possible that the BLE Scanner app you are using to decode the transmission is not decompressing properly. If you have an Android device, you might try my Locate Beacon app: https://play.google.com/store/apps/details?id=com.radiusnetworks.locate&hl=en