ChildOfCode


Code, Maker, Robotic, Open Source. Knowledge Bases


Android Java - Get Eddystone Beacon Service Data and Convert

On Android Eddystone beacon we can store some useful information inside Namespace and Instance to identify unique beacon.

Before Learn and Play CTF event. byte, ASCII text, Decimal and Hex is difficult thing for me. But after learning CTF this become very easy . since this kind of numbers is very common on CTF event.

Android Java API android.bluetooth.le.ScanRecord return Service Data is Decimal (bytes) . And Hex (bytes) is Eddystone Beacon support Specification, So we need to convert the Decimal (bytes) to get the Hex (bytes).

Eddystone UID frame broadcasts an opaque, unique 16-byte Beacon ID composed of a 10-byte namespace and a 6-byte instance.

We can use ASCII text for more readable and useful. We just need to convert the ASCII text to Hex and insert on beacon Namespace or Instance.

But on this POST we not using ASCII text since we just need Namespace and Instance Hex (bytes) to identify the beacon.
But remember we only have total 16bytes to store the text.

We need to Convert Byte array to Decimal string because Android Java API toString() method is not working on some older android phone with older Android OS their will alway return byte array . For compatible with older device our code will get Byte array and convert it.

Example: We can directly get ServiceData by
result.getScanRecord().getServiceData().toString()

and will get the result like
{0000feaa-0000-1000-8000-00805f9b34fb=[0, -65, 17, 34, 51, 68, 85, 102, 119, -120, -103, 0, 49, 50, 51, 52, 53, 54]}

But some android device will return byte array like [B@ee2583d

Example:

On Eddystone Beacon hardware setting

Namespace ID : 6865656C6F776F726C64

Instance ID : 313233343536

We Will Get the following result on Android

Android Java return Decimal (bytes)
104, 101, 108, 108, 111, 119, 111, 114, 108, 100, 49, 50, 51, 52, 53, 54

Convert to Hex (10 bytes) this will match what we set on beacon Namespace + Instance
68 65 6C 6C 6F 77 6F 72 6C 64 31 32 33 34 35 36

Convert to ASCII text
helloworld123456

 /* Android Java code - Get and convert Eddystone Beacon Service Data by childofcode.com */


private void processResult(ScanResult result) {

    String BytesArray = "";
    String RawAdvData = "";   
    String ServiceData = "";
    String Namespace = "";
    String Instance = "";

    // Process if ScanResult have result
    if (result.getScanRecord().getServiceUuids() != null) 
    {         
        // Use Android default UUID to scan beacon
        ParcelUuid EDDYSTONE_SERVICE_UUID = ParcelUuid.fromString("0000FEAA-0000-1000-8000-00805F9B34FB");
        byte[] EncodedServiceData = result.getScanRecord().getServiceData(EDDYSTONE_SERVICE_UUID);

        if (EncodedServiceData != null) 
        {
             try
             {

                // Convert Byte Array to Decimal (bytes) string
                ByteBuffer byteBuffer = ByteBuffer.wrap(EncodedServiceData);                
                BytesArray = Arrays.toString(byteBuffer.array());

                RawAdvData = BytesArray.toString();

             }
             catch (NumberFormatException nfe)
             {
                System.out.println("byteBuffer Exception ");  
             }             

            // Process if beacon advertisement have Service Data
            if (RawAdvData.length() > 0)    
            {
                int counter = 1;
                ArrayList<String> bytes = new ArrayList<String>();

                String asubstring = RawAdvData.substring(1, RawAdvData.length()-1); 
                String[] dataBytes = asubstring.split(",");

                for (String abytes : dataBytes) 
                {        
                    /*       
                    Eddystone-UID frame Byte offset we only need 10-byte Namespace and 6-byte Instance
                    0 and 1 Byte is Frame Type and Ranging Data and 18 and 19 Byte is Reserved for future use.
                    */
                    if(counter > 2)
                    {
                        try
                        {
                            // Convert Decimal (bytes) to Hex (bytes)
                            int theByte = Integer.parseInt(abytes.trim());  
                            String findUUID = Integer.toHexString(theByte);
                            String replacedString = findUUID.replace("ffffff", "");

                            if(replacedString.length() == 1)
                            {
                                bytes.add("0"+replacedString);
                            }
                            else
                            {
                                bytes.add(replacedString);
                            }   
                        }
                        catch (NumberFormatException nfe)
                        { 
                            System.out.println("Number Format Exception ");   
                        }
                    }
                    counter+=1;
                }

                ServiceData = bytes.toString(); 
                Namespace = ServiceData.substring(1, 35); 
                Instance = ServiceData.substring(37, ServiceData.length()-1); 
                System.out.println("ServiceData "+ServiceData);
                System.out.println("Namespace : "+Namespace);
                System.out.println("Instance : "+Instance);
            }
            else
            {
                ServiceData = ""; 
                System.out.println("ServiceData Empty "); 
            }
        }

    }

  }

Note: if you don't have any Beacon you can download a apps call "Beacon Simulator" on Google Play Store to simulate using android device .

refer:
https://github.com/google/eddystone/tree/master/eddystone-uid

https://developer.android.com/reference/android/bluetooth/le/ScanRecord#getServiceData()